blob: 35391ae0df7f1edad9304f2333af66a038f2dcb6 [file] [log] [blame]
Willy Tarreau91861262007-10-17 17:06:05 +02001/*
Willy Tarreaueb472682010-05-28 18:46:57 +02002 * Functions dedicated to statistics output and the stats socket
Willy Tarreau91861262007-10-17 17:06:05 +02003 *
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004 * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
Krzysztof Piotr Oledzki09605412009-09-23 22:09:24 +02005 * Copyright 2007-2009 Krzysztof Piotr Oledzki <ole@ans.pl>
Willy Tarreau91861262007-10-17 17:06:05 +02006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <ctype.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
Willy Tarreaufbee7132007-10-18 13:53:22 +020020#include <pwd.h>
21#include <grp.h>
Willy Tarreau91861262007-10-17 17:06:05 +020022
23#include <sys/socket.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26
Willy Tarreau10522fd2008-07-09 20:12:41 +020027#include <common/cfgparse.h>
Willy Tarreau91861262007-10-17 17:06:05 +020028#include <common/compat.h>
29#include <common/config.h>
30#include <common/debug.h>
31#include <common/memory.h>
32#include <common/mini-clist.h>
33#include <common/standard.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020034#include <common/ticks.h>
Willy Tarreau91861262007-10-17 17:06:05 +020035#include <common/time.h>
36#include <common/uri_auth.h>
37#include <common/version.h>
Emeric Brun4147b2e2014-06-16 18:36:30 +020038#include <common/base64.h>
Willy Tarreau91861262007-10-17 17:06:05 +020039
Willy Tarreau8a8d83b2015-04-13 13:24:54 +020040#include <types/applet.h>
Willy Tarreau91861262007-10-17 17:06:05 +020041#include <types/global.h>
Willy Tarreau91861262007-10-17 17:06:05 +020042
43#include <proto/backend.h>
Willy Tarreauc7e42382012-08-24 19:22:53 +020044#include <proto/channel.h>
Krzysztof Piotr Oledzki09605412009-09-23 22:09:24 +020045#include <proto/checks.h>
William Lallemande3a7d992012-11-20 11:25:20 +010046#include <proto/compression.h>
Willy Tarreau91861262007-10-17 17:06:05 +020047#include <proto/dumpstats.h>
48#include <proto/fd.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010049#include <proto/freq_ctr.h>
Willy Tarreau32b60d42015-03-13 16:14:57 +010050#include <proto/frontend.h>
Willy Tarreaueb472682010-05-28 18:46:57 +020051#include <proto/log.h>
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +010052#include <proto/pattern.h>
Willy Tarreaua206fa92009-01-25 14:02:00 +010053#include <proto/pipe.h>
Willy Tarreaud1d54542012-09-12 22:58:11 +020054#include <proto/listener.h>
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +010055#include <proto/map.h>
Willy Tarreaue6d97022012-11-23 11:19:33 +010056#include <proto/proto_http.h>
Willy Tarreaufbee7132007-10-18 13:53:22 +020057#include <proto/proto_uxst.h>
Willy Tarreau89a63132009-08-16 17:41:45 +020058#include <proto/proxy.h>
Willy Tarreau1cf8f082014-02-07 12:14:54 +010059#include <proto/sample.h>
Willy Tarreau9903f0e2015-04-04 18:50:31 +020060#include <proto/session.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020061#include <proto/stream.h>
Krzysztof Oledzki85130942007-10-22 16:21:10 +020062#include <proto/server.h>
Willy Tarreau75bf2c92012-08-20 17:01:35 +020063#include <proto/raw_sock.h>
Willy Tarreaudded32d2008-11-30 19:48:07 +010064#include <proto/stream_interface.h>
Willy Tarreau4726f532009-03-07 17:25:21 +010065#include <proto/task.h>
Willy Tarreau91861262007-10-17 17:06:05 +020066
Willy Tarreau7a0169a2012-11-19 17:13:16 +010067#ifdef USE_OPENSSL
68#include <proto/ssl_sock.h>
69#endif
70
Willy Tarreau91b843d2014-01-28 16:27:17 +010071/* stats socket states */
72enum {
73 STAT_CLI_INIT = 0, /* initial state, must leave to zero ! */
74 STAT_CLI_END, /* final state, let's close */
75 STAT_CLI_GETREQ, /* wait for a request */
76 STAT_CLI_OUTPUT, /* all states after this one are responses */
77 STAT_CLI_PROMPT, /* display the prompt (first output, same code) */
78 STAT_CLI_PRINT, /* display message in cli->msg */
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +010079 STAT_CLI_PRINT_FREE, /* display message in cli->msg. After the display, free the pointer */
Willy Tarreau91b843d2014-01-28 16:27:17 +010080 STAT_CLI_O_INFO, /* dump info */
Willy Tarreau87b09662015-04-03 00:22:06 +020081 STAT_CLI_O_SESS, /* dump streams */
Willy Tarreau91b843d2014-01-28 16:27:17 +010082 STAT_CLI_O_ERR, /* dump errors */
83 STAT_CLI_O_TAB, /* dump tables */
84 STAT_CLI_O_CLR, /* clear tables */
85 STAT_CLI_O_SET, /* set entries in tables */
86 STAT_CLI_O_STAT, /* dump stats */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +010087 STAT_CLI_O_PATS, /* list all pattern reference avalaible */
88 STAT_CLI_O_PAT, /* list all entries of a pattern */
Willy Tarreau91b843d2014-01-28 16:27:17 +010089 STAT_CLI_O_MLOOK, /* lookup a map entry */
Willy Tarreau12833bb2014-01-28 16:49:56 +010090 STAT_CLI_O_POOLS, /* dump memory pools */
Willy Tarreau91b843d2014-01-28 16:27:17 +010091};
92
Willy Tarreaued7df902014-05-22 18:04:49 +020093/* Actions available for the stats admin forms */
94enum {
95 ST_ADM_ACTION_NONE = 0,
Willy Tarreau248a60e2014-05-23 14:59:48 +020096
97 /* enable/disable health checks */
98 ST_ADM_ACTION_DHLTH,
99 ST_ADM_ACTION_EHLTH,
100
101 /* force health check status */
102 ST_ADM_ACTION_HRUNN,
103 ST_ADM_ACTION_HNOLB,
104 ST_ADM_ACTION_HDOWN,
105
106 /* enable/disable agent checks */
107 ST_ADM_ACTION_DAGENT,
108 ST_ADM_ACTION_EAGENT,
109
110 /* force agent check status */
111 ST_ADM_ACTION_ARUNN,
112 ST_ADM_ACTION_ADOWN,
113
114 /* set admin state */
Willy Tarreaued7df902014-05-22 18:04:49 +0200115 ST_ADM_ACTION_READY,
116 ST_ADM_ACTION_DRAIN,
117 ST_ADM_ACTION_MAINT,
118 ST_ADM_ACTION_SHUTDOWN,
119 /* these are the ancient actions, still available for compatibility */
120 ST_ADM_ACTION_DISABLE,
121 ST_ADM_ACTION_ENABLE,
122 ST_ADM_ACTION_STOP,
123 ST_ADM_ACTION_START,
124};
125
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +0100126static int stats_dump_info_to_buffer(struct stream_interface *si);
Willy Tarreau12833bb2014-01-28 16:49:56 +0100127static int stats_dump_pools_to_buffer(struct stream_interface *si);
Willy Tarreau87b09662015-04-03 00:22:06 +0200128static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct stream *sess);
Simon Horman9bd2c732011-06-15 15:18:44 +0900129static int stats_dump_sess_to_buffer(struct stream_interface *si);
130static int stats_dump_errors_to_buffer(struct stream_interface *si);
Willy Tarreau44455022012-12-05 23:01:12 +0100131static int stats_table_request(struct stream_interface *si, int show);
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +0100132static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy *px, struct uri_auth *uri);
133static int stats_dump_stat_to_buffer(struct stream_interface *si, struct uri_auth *uri);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100134static int stats_pats_list(struct stream_interface *si);
135static int stats_pat_list(struct stream_interface *si);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +0100136static int stats_map_lookup(struct stream_interface *si);
Willy Tarreau00a37f02015-04-13 12:05:19 +0200137static void cli_release_handler(struct appctx *appctx);
Simon Horman9bd2c732011-06-15 15:18:44 +0900138
Willy Tarreaud9bdcd52012-12-22 20:31:10 +0100139/*
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +0100140 * cli_io_handler()
141 * -> stats_dump_sess_to_buffer() // "show sess"
142 * -> stats_dump_errors_to_buffer() // "show errors"
143 * -> stats_dump_info_to_buffer() // "show info"
144 * -> stats_dump_stat_to_buffer() // "show stat"
145 * -> stats_dump_csv_header()
146 * -> stats_dump_proxy_to_buffer()
147 * -> stats_dump_fe_stats()
148 * -> stats_dump_li_stats()
149 * -> stats_dump_sv_stats()
150 * -> stats_dump_be_stats()
151 *
152 * http_stats_io_handler()
153 * -> stats_dump_stat_to_buffer() // same as above, but used for CSV or HTML
154 * -> stats_dump_csv_header() // emits the CSV headers (same as above)
155 * -> stats_dump_html_head() // emits the HTML headers
156 * -> stats_dump_html_info() // emits the equivalent of "show info" at the top
157 * -> stats_dump_proxy_to_buffer() // same as above, valid for CSV and HTML
158 * -> stats_dump_html_px_hdr()
159 * -> stats_dump_fe_stats()
160 * -> stats_dump_li_stats()
161 * -> stats_dump_sv_stats()
162 * -> stats_dump_be_stats()
163 * -> stats_dump_html_px_end()
164 * -> stats_dump_html_end() // emits HTML trailer
Willy Tarreaud9bdcd52012-12-22 20:31:10 +0100165 */
166
Willy Tarreau30576452015-04-13 13:50:30 +0200167static struct applet cli_applet;
Simon Horman9bd2c732011-06-15 15:18:44 +0900168
169static const char stats_sock_usage_msg[] =
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +0200170 "Unknown command. Please enter one of the following commands only :\n"
Willy Tarreau2f6bf2b2009-10-10 15:26:26 +0200171 " clear counters : clear max statistics counters (add 'all' for all counters)\n"
Willy Tarreau88ee3972010-07-13 13:48:00 +0200172 " clear table : remove an entry from a table\n"
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +0200173 " help : this message\n"
174 " prompt : toggle interactive mode with prompt\n"
175 " quit : disconnect\n"
176 " show info : report information about the running process\n"
Willy Tarreau12833bb2014-01-28 16:49:56 +0100177 " show pools : report information about the memory pools usage\n"
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +0200178 " show stat : report counters for each proxy and server\n"
179 " show errors : report last request and response errors for each proxy\n"
Willy Tarreau66dc20a2010-03-05 17:53:32 +0100180 " show sess [id] : report the list of current sessions or dump this session\n"
Willy Tarreau69f58c82010-07-12 17:55:33 +0200181 " show table [id]: report table usage stats or dump this table's contents\n"
Willy Tarreau38338fa2009-10-10 18:37:29 +0200182 " get weight : report a server's current weight\n"
Willy Tarreau4483d432009-10-10 19:30:08 +0200183 " set weight : change a server's weight\n"
Willy Tarreau2a4b70f2014-05-22 18:42:35 +0200184 " set server : change a server's state or weight\n"
Willy Tarreau654694e2012-06-07 01:03:16 +0200185 " set table [id] : update or create a table entry's data\n"
Willy Tarreau7aabd112010-01-26 10:59:06 +0100186 " set timeout : change a timeout setting\n"
Willy Tarreau2a0f4d22011-08-02 11:49:05 +0200187 " set maxconn : change a maxconn setting\n"
Willy Tarreauf5b22872011-09-07 16:13:44 +0200188 " set rate-limit : change a rate limiting value\n"
Willy Tarreaua295edc2011-09-07 23:21:03 +0200189 " disable : put a server or frontend in maintenance mode\n"
190 " enable : re-enable a server or frontend which is in maintenance mode\n"
191 " shutdown : kill a session or a frontend (eg:to release listening ports)\n"
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100192 " show acl [id] : report avalaible acls or dump an acl's contents\n"
193 " get acl : reports the patterns matching a sample for an ACL\n"
194 " add acl : add acl entry\n"
195 " del acl : delete acl entry\n"
196 " clear acl <id> : clear the content of this acl\n"
Thierry FOURNIER1432a0c2014-03-11 13:42:38 +0100197 " show map [id] : report avalaible maps or dump a map's contents\n"
198 " get map : reports the keys and values matching a sample for a map\n"
199 " set map : modify map entry\n"
200 " add map : add map entry\n"
201 " del map : delete map entry\n"
202 " clear map <id> : clear the content of this map\n"
Emeric Brun4147b2e2014-06-16 18:36:30 +0200203 " set ssl <stmt> : set statement for ssl\n"
Willy Tarreau9a42c0d2009-09-22 19:31:03 +0200204 "";
Willy Tarreau5ca791d2009-08-16 19:06:42 +0200205
Simon Horman9bd2c732011-06-15 15:18:44 +0900206static const char stats_permission_denied_msg[] =
Willy Tarreau6162db22009-10-10 17:13:00 +0200207 "Permission denied\n"
208 "";
209
Willy Tarreau295a8372011-03-10 11:25:07 +0100210/* data transmission states for the stats responses */
211enum {
212 STAT_ST_INIT = 0,
213 STAT_ST_HEAD,
214 STAT_ST_INFO,
215 STAT_ST_LIST,
216 STAT_ST_END,
217 STAT_ST_FIN,
218};
219
220/* data transmission states for the stats responses inside a proxy */
221enum {
222 STAT_PX_ST_INIT = 0,
223 STAT_PX_ST_TH,
224 STAT_PX_ST_FE,
225 STAT_PX_ST_LI,
226 STAT_PX_ST_SV,
227 STAT_PX_ST_BE,
228 STAT_PX_ST_END,
229 STAT_PX_ST_FIN,
230};
231
Cyril Bonté19979e12012-04-04 12:57:21 +0200232extern const char *stat_status_codes[];
233
Willy Tarreau07e9e642010-08-17 21:48:17 +0200234/* allocate a new stats frontend named <name>, and return it
235 * (or NULL in case of lack of memory).
236 */
Willy Tarreaua020fbd2012-09-18 20:05:00 +0200237static struct proxy *alloc_stats_fe(const char *name, const char *file, int line)
Willy Tarreau07e9e642010-08-17 21:48:17 +0200238{
239 struct proxy *fe;
240
241 fe = (struct proxy *)calloc(1, sizeof(struct proxy));
242 if (!fe)
243 return NULL;
244
Willy Tarreau237250c2011-07-29 01:49:03 +0200245 init_new_proxy(fe);
Willy Tarreau050536d2012-10-04 08:47:34 +0200246 fe->next = proxy;
247 proxy = fe;
Willy Tarreau07e9e642010-08-17 21:48:17 +0200248 fe->last_change = now.tv_sec;
249 fe->id = strdup("GLOBAL");
250 fe->cap = PR_CAP_FE;
Willy Tarreauc2adf8b2011-09-07 12:13:34 +0200251 fe->maxconn = 10; /* default to 10 concurrent connections */
252 fe->timeout.client = MS_TO_TICKS(10000); /* default timeout of 10 seconds */
Willy Tarreaua020fbd2012-09-18 20:05:00 +0200253 fe->conf.file = strdup(file);
254 fe->conf.line = line;
Willy Tarreau32b60d42015-03-13 16:14:57 +0100255 fe->accept = frontend_accept;
Willy Tarreauf87ab942015-03-13 15:55:16 +0100256 fe->default_target = &cli_applet.obj_type;
Willy Tarreau050536d2012-10-04 08:47:34 +0200257
258 /* the stats frontend is the only one able to assign ID #0 */
259 fe->conf.id.key = fe->uuid = 0;
260 eb32_insert(&used_proxy_id, &fe->conf.id);
Willy Tarreau07e9e642010-08-17 21:48:17 +0200261 return fe;
262}
263
Willy Tarreaufbee7132007-10-18 13:53:22 +0200264/* This function parses a "stats" statement in the "global" section. It returns
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200265 * -1 if there is any error, otherwise zero. If it returns -1, it will write an
266 * error message into the <err> buffer which will be preallocated. The trailing
267 * '\n' must not be written. The function must be called with <args> pointing to
268 * the first word after "stats".
Willy Tarreaufbee7132007-10-18 13:53:22 +0200269 */
Willy Tarreau10522fd2008-07-09 20:12:41 +0200270static int stats_parse_global(char **args, int section_type, struct proxy *curpx,
Willy Tarreau28a47d62012-09-18 20:02:48 +0200271 struct proxy *defpx, const char *file, int line,
272 char **err)
Willy Tarreaufbee7132007-10-18 13:53:22 +0200273{
Willy Tarreau4348fad2012-09-20 16:48:07 +0200274 struct bind_conf *bind_conf;
Willy Tarreauc53d4222012-09-20 20:19:28 +0200275 struct listener *l;
Willy Tarreau4348fad2012-09-20 16:48:07 +0200276
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200277 if (!strcmp(args[1], "socket")) {
Willy Tarreaufbee7132007-10-18 13:53:22 +0200278 int cur_arg;
279
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200280 if (*args[2] == 0) {
Willy Tarreauc53d4222012-09-20 20:19:28 +0200281 memprintf(err, "'%s %s' in global section expects an address or a path to a UNIX socket", args[0], args[1]);
Willy Tarreaufbee7132007-10-18 13:53:22 +0200282 return -1;
283 }
284
Willy Tarreau89a63132009-08-16 17:41:45 +0200285 if (!global.stats_fe) {
Willy Tarreaua020fbd2012-09-18 20:05:00 +0200286 if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200287 memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
Willy Tarreau89a63132009-08-16 17:41:45 +0200288 return -1;
289 }
Willy Tarreau89a63132009-08-16 17:41:45 +0200290 }
291
Willy Tarreau4348fad2012-09-20 16:48:07 +0200292 bind_conf = bind_conf_alloc(&global.stats_fe->conf.bind, file, line, args[2]);
Willy Tarreau290e63a2012-09-20 18:07:14 +0200293 bind_conf->level = ACCESS_LVL_OPER; /* default access level */
Willy Tarreau4348fad2012-09-20 16:48:07 +0200294
Willy Tarreauc53d4222012-09-20 20:19:28 +0200295 if (!str2listener(args[2], global.stats_fe, bind_conf, file, line, err)) {
296 memprintf(err, "parsing [%s:%d] : '%s %s' : %s\n",
297 file, line, args[0], args[1], err && *err ? *err : "error");
298 return -1;
299 }
Willy Tarreaufbee7132007-10-18 13:53:22 +0200300
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200301 cur_arg = 3;
Willy Tarreaufbee7132007-10-18 13:53:22 +0200302 while (*args[cur_arg]) {
Willy Tarreaud5781202012-09-22 19:32:35 +0200303 static int bind_dumped;
304 struct bind_kw *kw;
305
306 kw = bind_find_kw(args[cur_arg]);
307 if (kw) {
308 if (!kw->parse) {
309 memprintf(err, "'%s %s' : '%s' option is not implemented in this version (check build options).",
310 args[0], args[1], args[cur_arg]);
Willy Tarreaufbee7132007-10-18 13:53:22 +0200311 return -1;
312 }
Willy Tarreaud5781202012-09-22 19:32:35 +0200313
314 if (kw->parse(args, cur_arg, curpx, bind_conf, err) != 0) {
315 if (err && *err)
316 memprintf(err, "'%s %s' : '%s'", args[0], args[1], *err);
317 else
318 memprintf(err, "'%s %s' : error encountered while processing '%s'",
319 args[0], args[1], args[cur_arg]);
Willy Tarreau6162db22009-10-10 17:13:00 +0200320 return -1;
321 }
Willy Tarreaud5781202012-09-22 19:32:35 +0200322
323 cur_arg += 1 + kw->skip;
324 continue;
Willy Tarreau6162db22009-10-10 17:13:00 +0200325 }
Willy Tarreaud5781202012-09-22 19:32:35 +0200326
327 if (!bind_dumped) {
328 bind_dump_kws(err);
329 indent_msg(err, 4);
330 bind_dumped = 1;
Willy Tarreaufbee7132007-10-18 13:53:22 +0200331 }
Willy Tarreaud5781202012-09-22 19:32:35 +0200332
333 memprintf(err, "'%s %s' : unknown keyword '%s'.%s%s",
334 args[0], args[1], args[cur_arg],
335 err && *err ? " Registered keywords :" : "", err && *err ? *err : "");
336 return -1;
Willy Tarreaufbee7132007-10-18 13:53:22 +0200337 }
Willy Tarreaub1356cf2008-12-07 16:06:43 +0100338
Willy Tarreauc53d4222012-09-20 20:19:28 +0200339 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
340 l->maxconn = global.stats_fe->maxconn;
341 l->backlog = global.stats_fe->backlog;
Willy Tarreau9903f0e2015-04-04 18:50:31 +0200342 l->accept = session_accept_fd;
Willy Tarreau87b09662015-04-03 00:22:06 +0200343 l->handler = process_stream;
Willy Tarreau10b688f2015-03-13 16:43:12 +0100344 l->default_target = global.stats_fe->default_target;
Willy Tarreauc53d4222012-09-20 20:19:28 +0200345 l->options |= LI_O_UNLIMITED; /* don't make the peers subject to global limits */
346 l->nice = -64; /* we want to boost priority for local stats */
347 global.maxsock += l->maxconn;
348 }
Willy Tarreaufbee7132007-10-18 13:53:22 +0200349 }
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200350 else if (!strcmp(args[1], "timeout")) {
Willy Tarreaub3f32f52007-12-02 22:15:14 +0100351 unsigned timeout;
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200352 const char *res = parse_time_err(args[2], &timeout, TIME_UNIT_MS);
Willy Tarreaub3f32f52007-12-02 22:15:14 +0100353
354 if (res) {
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200355 memprintf(err, "'%s %s' : unexpected character '%c'", args[0], args[1], *res);
Willy Tarreaub3f32f52007-12-02 22:15:14 +0100356 return -1;
357 }
Willy Tarreaufbee7132007-10-18 13:53:22 +0200358
Willy Tarreaub3f32f52007-12-02 22:15:14 +0100359 if (!timeout) {
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200360 memprintf(err, "'%s %s' expects a positive value", args[0], args[1]);
Willy Tarreaufbee7132007-10-18 13:53:22 +0200361 return -1;
362 }
Willy Tarreau07e9e642010-08-17 21:48:17 +0200363 if (!global.stats_fe) {
Willy Tarreaua020fbd2012-09-18 20:05:00 +0200364 if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200365 memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
Willy Tarreau07e9e642010-08-17 21:48:17 +0200366 return -1;
367 }
368 }
Willy Tarreau89a63132009-08-16 17:41:45 +0200369 global.stats_fe->timeout.client = MS_TO_TICKS(timeout);
Willy Tarreaufbee7132007-10-18 13:53:22 +0200370 }
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200371 else if (!strcmp(args[1], "maxconn")) {
372 int maxconn = atol(args[2]);
Willy Tarreaufbee7132007-10-18 13:53:22 +0200373
374 if (maxconn <= 0) {
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200375 memprintf(err, "'%s %s' expects a positive value", args[0], args[1]);
Willy Tarreaufbee7132007-10-18 13:53:22 +0200376 return -1;
377 }
Willy Tarreauc2adf8b2011-09-07 12:13:34 +0200378
379 if (!global.stats_fe) {
Willy Tarreaua020fbd2012-09-18 20:05:00 +0200380 if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
Willy Tarreau0a3dd742012-05-08 19:47:01 +0200381 memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
Willy Tarreauc2adf8b2011-09-07 12:13:34 +0200382 return -1;
383 }
384 }
385 global.stats_fe->maxconn = maxconn;
Willy Tarreaufbee7132007-10-18 13:53:22 +0200386 }
Willy Tarreau35b7b162012-10-22 23:17:18 +0200387 else if (!strcmp(args[1], "bind-process")) { /* enable the socket only on some processes */
388 int cur_arg = 2;
Willy Tarreaua9db57e2013-01-18 11:29:29 +0100389 unsigned long set = 0;
Willy Tarreau35b7b162012-10-22 23:17:18 +0200390
Willy Tarreau91319572013-04-20 09:48:50 +0200391 if (!global.stats_fe) {
392 if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
393 memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
394 return -1;
395 }
396 }
397
Willy Tarreau35b7b162012-10-22 23:17:18 +0200398 while (*args[cur_arg]) {
Willy Tarreau110ecc12012-11-15 17:50:01 +0100399 unsigned int low, high;
400
Willy Tarreau35b7b162012-10-22 23:17:18 +0200401 if (strcmp(args[cur_arg], "all") == 0) {
402 set = 0;
403 break;
404 }
405 else if (strcmp(args[cur_arg], "odd") == 0) {
Willy Tarreaua9db57e2013-01-18 11:29:29 +0100406 set |= ~0UL/3UL; /* 0x555....555 */
Willy Tarreau35b7b162012-10-22 23:17:18 +0200407 }
408 else if (strcmp(args[cur_arg], "even") == 0) {
Willy Tarreaua9db57e2013-01-18 11:29:29 +0100409 set |= (~0UL/3UL) << 1; /* 0xAAA...AAA */
Willy Tarreau35b7b162012-10-22 23:17:18 +0200410 }
Willy Tarreau83d84cf2012-11-22 01:04:31 +0100411 else if (isdigit((int)*args[cur_arg])) {
Willy Tarreau110ecc12012-11-15 17:50:01 +0100412 char *dash = strchr(args[cur_arg], '-');
413
414 low = high = str2uic(args[cur_arg]);
415 if (dash)
416 high = str2uic(dash + 1);
417
418 if (high < low) {
419 unsigned int swap = low;
420 low = high;
421 high = swap;
422 }
423
Willy Tarreaua9db57e2013-01-18 11:29:29 +0100424 if (low < 1 || high > LONGBITS) {
425 memprintf(err, "'%s %s' supports process numbers from 1 to %d.\n",
426 args[0], args[1], LONGBITS);
Willy Tarreau35b7b162012-10-22 23:17:18 +0200427 return -1;
428 }
Willy Tarreau110ecc12012-11-15 17:50:01 +0100429 while (low <= high)
Willy Tarreaua9db57e2013-01-18 11:29:29 +0100430 set |= 1UL << (low++ - 1);
Willy Tarreau110ecc12012-11-15 17:50:01 +0100431 }
432 else {
433 memprintf(err,
Willy Tarreaua9db57e2013-01-18 11:29:29 +0100434 "'%s %s' expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to %d.\n",
435 args[0], args[1], LONGBITS);
Willy Tarreau110ecc12012-11-15 17:50:01 +0100436 return -1;
Willy Tarreau35b7b162012-10-22 23:17:18 +0200437 }
438 cur_arg++;
439 }
440 global.stats_fe->bind_proc = set;
441 }
Willy Tarreaufbee7132007-10-18 13:53:22 +0200442 else {
Willy Tarreau35b7b162012-10-22 23:17:18 +0200443 memprintf(err, "'%s' only supports 'socket', 'maxconn', 'bind-process' and 'timeout' (got '%s')", args[0], args[1]);
Willy Tarreaufbee7132007-10-18 13:53:22 +0200444 return -1;
445 }
446 return 0;
447}
448
Willy Tarreaud9bdcd52012-12-22 20:31:10 +0100449/* Dumps the stats CSV header to the trash buffer which. The caller is responsible
450 * for clearing it if needed.
Willy Tarreauf522f3d2014-02-10 22:22:49 +0100451 * NOTE: Some tools happen to rely on the field position instead of its name,
452 * so please only append new fields at the end, never in the middle.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +0100453 */
454static void stats_dump_csv_header()
Willy Tarreau4bab24d2007-11-30 18:16:29 +0100455{
Willy Tarreaud9bdcd52012-12-22 20:31:10 +0100456 chunk_appendf(&trash,
457 "# pxname,svname,"
458 "qcur,qmax,"
Willy Tarreauf522f3d2014-02-10 22:22:49 +0100459 "scur,smax,slim,stot,"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +0100460 "bin,bout,"
461 "dreq,dresp,"
462 "ereq,econ,eresp,"
463 "wretr,wredis,"
464 "status,weight,act,bck,"
465 "chkfail,chkdown,lastchg,downtime,qlimit,"
466 "pid,iid,sid,throttle,lbtot,tracked,type,"
467 "rate,rate_lim,rate_max,"
468 "check_status,check_code,check_duration,"
469 "hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,"
470 "req_rate,req_rate_max,req_tot,"
471 "cli_abrt,srv_abrt,"
Willy Tarreauf5b1cc32014-06-17 12:20:59 +0200472 "comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,last_agt,qtime,ctime,rtime,ttime,"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +0100473 "\n");
Willy Tarreau4bab24d2007-11-30 18:16:29 +0100474}
475
Simon Hormand9366582011-06-15 15:18:45 +0900476/* print a string of text buffer to <out>. The format is :
477 * Non-printable chars \t, \n, \r and \e are * encoded in C format.
478 * Other non-printable chars are encoded "\xHH". Space and '\' are also escaped.
479 * Print stopped if null char or <bsize> is reached, or if no more place in the chunk.
480 */
481static int dump_text(struct chunk *out, const char *buf, int bsize)
482{
483 unsigned char c;
484 int ptr = 0;
485
486 while (buf[ptr] && ptr < bsize) {
487 c = buf[ptr];
488 if (isprint(c) && isascii(c) && c != '\\' && c != ' ') {
489 if (out->len > out->size - 1)
490 break;
491 out->str[out->len++] = c;
492 }
493 else if (c == '\t' || c == '\n' || c == '\r' || c == '\e' || c == '\\' || c == ' ') {
494 if (out->len > out->size - 2)
495 break;
496 out->str[out->len++] = '\\';
497 switch (c) {
498 case ' ': c = ' '; break;
499 case '\t': c = 't'; break;
500 case '\n': c = 'n'; break;
501 case '\r': c = 'r'; break;
502 case '\e': c = 'e'; break;
503 case '\\': c = '\\'; break;
504 }
505 out->str[out->len++] = c;
506 }
507 else {
508 if (out->len > out->size - 4)
509 break;
510 out->str[out->len++] = '\\';
511 out->str[out->len++] = 'x';
512 out->str[out->len++] = hextab[(c >> 4) & 0xF];
513 out->str[out->len++] = hextab[c & 0xF];
514 }
515 ptr++;
516 }
517
518 return ptr;
519}
520
521/* print a buffer in hexa.
522 * Print stopped if <bsize> is reached, or if no more place in the chunk.
523 */
524static int dump_binary(struct chunk *out, const char *buf, int bsize)
525{
526 unsigned char c;
527 int ptr = 0;
528
529 while (ptr < bsize) {
530 c = buf[ptr];
531
532 if (out->len > out->size - 2)
533 break;
534 out->str[out->len++] = hextab[(c >> 4) & 0xF];
535 out->str[out->len++] = hextab[c & 0xF];
536
537 ptr++;
538 }
539 return ptr;
540}
541
542/* Dump the status of a table to a stream interface's
543 * read buffer. It returns 0 if the output buffer is full
544 * and needs to be called again, otherwise non-zero.
545 */
546static int stats_dump_table_head_to_buffer(struct chunk *msg, struct stream_interface *si,
547 struct proxy *proxy, struct proxy *target)
548{
Willy Tarreau87b09662015-04-03 00:22:06 +0200549 struct stream *s = si_strm(si);
Simon Hormand9366582011-06-15 15:18:45 +0900550
Willy Tarreau77804732012-10-29 16:14:26 +0100551 chunk_appendf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
Simon Hormand9366582011-06-15 15:18:45 +0900552 proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
553
554 /* any other information should be dumped here */
555
Willy Tarreaud0d8da92015-04-04 02:10:38 +0200556 if (target && strm_li(s)->bind_conf->level < ACCESS_LVL_OPER)
Willy Tarreau77804732012-10-29 16:14:26 +0100557 chunk_appendf(msg, "# contents not dumped due to insufficient privileges\n");
Simon Hormand9366582011-06-15 15:18:45 +0900558
Willy Tarreaubc18da12015-03-13 14:00:47 +0100559 if (bi_putchk(si_ic(si), msg) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +0200560 si_applet_cant_put(si);
Simon Hormand9366582011-06-15 15:18:45 +0900561 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +0100562 }
Simon Hormand9366582011-06-15 15:18:45 +0900563
564 return 1;
565}
566
567/* Dump the a table entry to a stream interface's
568 * read buffer. It returns 0 if the output buffer is full
569 * and needs to be called again, otherwise non-zero.
570 */
571static int stats_dump_table_entry_to_buffer(struct chunk *msg, struct stream_interface *si,
572 struct proxy *proxy, struct stksess *entry)
573{
574 int dt;
575
Willy Tarreau77804732012-10-29 16:14:26 +0100576 chunk_appendf(msg, "%p:", entry);
Simon Hormand9366582011-06-15 15:18:45 +0900577
578 if (proxy->table.type == STKTABLE_TYPE_IP) {
579 char addr[INET_ADDRSTRLEN];
580 inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
Willy Tarreau77804732012-10-29 16:14:26 +0100581 chunk_appendf(msg, " key=%s", addr);
Simon Hormand9366582011-06-15 15:18:45 +0900582 }
583 else if (proxy->table.type == STKTABLE_TYPE_IPV6) {
584 char addr[INET6_ADDRSTRLEN];
585 inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
Willy Tarreau77804732012-10-29 16:14:26 +0100586 chunk_appendf(msg, " key=%s", addr);
Simon Hormand9366582011-06-15 15:18:45 +0900587 }
588 else if (proxy->table.type == STKTABLE_TYPE_INTEGER) {
Willy Tarreau77804732012-10-29 16:14:26 +0100589 chunk_appendf(msg, " key=%u", *(unsigned int *)entry->key.key);
Simon Hormand9366582011-06-15 15:18:45 +0900590 }
591 else if (proxy->table.type == STKTABLE_TYPE_STRING) {
Willy Tarreau77804732012-10-29 16:14:26 +0100592 chunk_appendf(msg, " key=");
Simon Hormand9366582011-06-15 15:18:45 +0900593 dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
594 }
595 else {
Willy Tarreau77804732012-10-29 16:14:26 +0100596 chunk_appendf(msg, " key=");
Simon Hormand9366582011-06-15 15:18:45 +0900597 dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
598 }
599
Willy Tarreau77804732012-10-29 16:14:26 +0100600 chunk_appendf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
Simon Hormand9366582011-06-15 15:18:45 +0900601
602 for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
603 void *ptr;
604
605 if (proxy->table.data_ofs[dt] == 0)
606 continue;
607 if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
Willy Tarreau77804732012-10-29 16:14:26 +0100608 chunk_appendf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
Simon Hormand9366582011-06-15 15:18:45 +0900609 else
Willy Tarreau77804732012-10-29 16:14:26 +0100610 chunk_appendf(msg, " %s=", stktable_data_types[dt].name);
Simon Hormand9366582011-06-15 15:18:45 +0900611
612 ptr = stktable_data_ptr(&proxy->table, entry, dt);
613 switch (stktable_data_types[dt].std_type) {
614 case STD_T_SINT:
Willy Tarreau77804732012-10-29 16:14:26 +0100615 chunk_appendf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
Simon Hormand9366582011-06-15 15:18:45 +0900616 break;
617 case STD_T_UINT:
Willy Tarreau77804732012-10-29 16:14:26 +0100618 chunk_appendf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
Simon Hormand9366582011-06-15 15:18:45 +0900619 break;
620 case STD_T_ULL:
Willy Tarreau77804732012-10-29 16:14:26 +0100621 chunk_appendf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
Simon Hormand9366582011-06-15 15:18:45 +0900622 break;
623 case STD_T_FRQP:
Willy Tarreau77804732012-10-29 16:14:26 +0100624 chunk_appendf(msg, "%d",
Simon Hormand9366582011-06-15 15:18:45 +0900625 read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
626 proxy->table.data_arg[dt].u));
627 break;
628 }
629 }
Willy Tarreau77804732012-10-29 16:14:26 +0100630 chunk_appendf(msg, "\n");
Simon Hormand9366582011-06-15 15:18:45 +0900631
Willy Tarreaubc18da12015-03-13 14:00:47 +0100632 if (bi_putchk(si_ic(si), msg) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +0200633 si_applet_cant_put(si);
Simon Hormand9366582011-06-15 15:18:45 +0900634 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +0100635 }
Simon Hormand9366582011-06-15 15:18:45 +0900636
637 return 1;
638}
639
Willy Tarreaudec98142012-06-06 23:37:08 +0200640static void stats_sock_table_key_request(struct stream_interface *si, char **args, int action)
Simon Horman121f3052011-06-15 15:18:46 +0900641{
Willy Tarreau87b09662015-04-03 00:22:06 +0200642 struct stream *s = si_strm(si);
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100643 struct appctx *appctx = __objt_appctx(si->end);
644 struct proxy *px = appctx->ctx.table.target;
Simon Horman121f3052011-06-15 15:18:46 +0900645 struct stksess *ts;
Simon Hormancec9a222011-06-15 15:18:51 +0900646 uint32_t uint32_key;
Simon Hormanc5b89f62011-06-15 15:18:50 +0900647 unsigned char ip6_key[sizeof(struct in6_addr)];
Willy Tarreau654694e2012-06-07 01:03:16 +0200648 long long value;
649 int data_type;
Willy Tarreau47060b62013-08-01 21:11:42 +0200650 int cur_arg;
Willy Tarreau654694e2012-06-07 01:03:16 +0200651 void *ptr;
652 struct freq_ctr_period *frqp;
Simon Horman121f3052011-06-15 15:18:46 +0900653
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100654 appctx->st0 = STAT_CLI_OUTPUT;
Simon Horman121f3052011-06-15 15:18:46 +0900655
656 if (!*args[4]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100657 appctx->ctx.cli.msg = "Key value expected\n";
658 appctx->st0 = STAT_CLI_PRINT;
Simon Horman121f3052011-06-15 15:18:46 +0900659 return;
660 }
661
Simon Hormanc5b89f62011-06-15 15:18:50 +0900662 switch (px->table.type) {
663 case STKTABLE_TYPE_IP:
Simon Hormancec9a222011-06-15 15:18:51 +0900664 uint32_key = htonl(inetaddr_host(args[4]));
Willy Tarreau07115412012-10-29 21:56:59 +0100665 static_table_key->key = &uint32_key;
Simon Hormanc5b89f62011-06-15 15:18:50 +0900666 break;
667 case STKTABLE_TYPE_IPV6:
668 inet_pton(AF_INET6, args[4], ip6_key);
Willy Tarreau07115412012-10-29 21:56:59 +0100669 static_table_key->key = &ip6_key;
Simon Hormanc5b89f62011-06-15 15:18:50 +0900670 break;
Simon Hormancec9a222011-06-15 15:18:51 +0900671 case STKTABLE_TYPE_INTEGER:
672 {
673 char *endptr;
674 unsigned long val;
675 errno = 0;
676 val = strtoul(args[4], &endptr, 10);
677 if ((errno == ERANGE && val == ULONG_MAX) ||
678 (errno != 0 && val == 0) || endptr == args[4] ||
679 val > 0xffffffff) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100680 appctx->ctx.cli.msg = "Invalid key\n";
681 appctx->st0 = STAT_CLI_PRINT;
Simon Hormancec9a222011-06-15 15:18:51 +0900682 return;
683 }
684 uint32_key = (uint32_t) val;
Willy Tarreau07115412012-10-29 21:56:59 +0100685 static_table_key->key = &uint32_key;
Simon Hormancec9a222011-06-15 15:18:51 +0900686 break;
687 }
688 break;
Simon Horman619e3cc2011-06-15 15:18:52 +0900689 case STKTABLE_TYPE_STRING:
Willy Tarreau07115412012-10-29 21:56:59 +0100690 static_table_key->key = args[4];
691 static_table_key->key_len = strlen(args[4]);
Simon Horman619e3cc2011-06-15 15:18:52 +0900692 break;
Simon Hormanc5b89f62011-06-15 15:18:50 +0900693 default:
Willy Tarreaudec98142012-06-06 23:37:08 +0200694 switch (action) {
695 case STAT_CLI_O_TAB:
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100696 appctx->ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
Willy Tarreaudec98142012-06-06 23:37:08 +0200697 break;
698 case STAT_CLI_O_CLR:
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100699 appctx->ctx.cli.msg = "Removing keys from ip tables of type other than ip, ipv6, string and integer is not supported\n";
Willy Tarreaudec98142012-06-06 23:37:08 +0200700 break;
701 default:
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100702 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreaudec98142012-06-06 23:37:08 +0200703 break;
704 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100705 appctx->st0 = STAT_CLI_PRINT;
Simon Horman121f3052011-06-15 15:18:46 +0900706 return;
707 }
708
709 /* check permissions */
Willy Tarreaud0d8da92015-04-04 02:10:38 +0200710 if (strm_li(s)->bind_conf->level < ACCESS_LVL_OPER) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100711 appctx->ctx.cli.msg = stats_permission_denied_msg;
712 appctx->st0 = STAT_CLI_PRINT;
Simon Horman121f3052011-06-15 15:18:46 +0900713 return;
714 }
715
Willy Tarreau07115412012-10-29 21:56:59 +0100716 ts = stktable_lookup_key(&px->table, static_table_key);
Simon Horman17bce342011-06-15 15:18:47 +0900717
Willy Tarreaudec98142012-06-06 23:37:08 +0200718 switch (action) {
719 case STAT_CLI_O_TAB:
720 if (!ts)
721 return;
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100722 chunk_reset(&trash);
723 if (!stats_dump_table_head_to_buffer(&trash, si, px, px))
Simon Horman17bce342011-06-15 15:18:47 +0900724 return;
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100725 stats_dump_table_entry_to_buffer(&trash, si, px, ts);
Simon Horman121f3052011-06-15 15:18:46 +0900726 return;
Willy Tarreaudec98142012-06-06 23:37:08 +0200727
728 case STAT_CLI_O_CLR:
729 if (!ts)
730 return;
731 if (ts->ref_cnt) {
732 /* don't delete an entry which is currently referenced */
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100733 appctx->ctx.cli.msg = "Entry currently in use, cannot remove\n";
734 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaudec98142012-06-06 23:37:08 +0200735 return;
736 }
737 stksess_kill(&px->table, ts);
738 break;
Simon Horman17bce342011-06-15 15:18:47 +0900739
Willy Tarreau654694e2012-06-07 01:03:16 +0200740 case STAT_CLI_O_SET:
Willy Tarreau654694e2012-06-07 01:03:16 +0200741 if (ts)
742 stktable_touch(&px->table, ts, 1);
743 else {
Willy Tarreau07115412012-10-29 21:56:59 +0100744 ts = stksess_new(&px->table, static_table_key);
Willy Tarreau654694e2012-06-07 01:03:16 +0200745 if (!ts) {
746 /* don't delete an entry which is currently referenced */
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100747 appctx->ctx.cli.msg = "Unable to allocate a new entry\n";
748 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau654694e2012-06-07 01:03:16 +0200749 return;
750 }
751 stktable_store(&px->table, ts, 1);
752 }
753
Willy Tarreau47060b62013-08-01 21:11:42 +0200754 for (cur_arg = 5; *args[cur_arg]; cur_arg += 2) {
755 if (strncmp(args[cur_arg], "data.", 5) != 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100756 appctx->ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
757 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau47060b62013-08-01 21:11:42 +0200758 return;
759 }
760
761 data_type = stktable_get_data_type(args[cur_arg] + 5);
762 if (data_type < 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100763 appctx->ctx.cli.msg = "Unknown data type\n";
764 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau47060b62013-08-01 21:11:42 +0200765 return;
766 }
767
768 if (!px->table.data_ofs[data_type]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100769 appctx->ctx.cli.msg = "Data type not stored in this table\n";
770 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau47060b62013-08-01 21:11:42 +0200771 return;
772 }
773
774 if (!*args[cur_arg+1] || strl2llrc(args[cur_arg+1], strlen(args[cur_arg+1]), &value) != 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100775 appctx->ctx.cli.msg = "Require a valid integer value to store\n";
776 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau47060b62013-08-01 21:11:42 +0200777 return;
778 }
779
780 ptr = stktable_data_ptr(&px->table, ts, data_type);
781
782 switch (stktable_data_types[data_type].std_type) {
783 case STD_T_SINT:
784 stktable_data_cast(ptr, std_t_sint) = value;
785 break;
786 case STD_T_UINT:
787 stktable_data_cast(ptr, std_t_uint) = value;
788 break;
789 case STD_T_ULL:
790 stktable_data_cast(ptr, std_t_ull) = value;
791 break;
792 case STD_T_FRQP:
793 /* We set both the current and previous values. That way
794 * the reported frequency is stable during all the period
795 * then slowly fades out. This allows external tools to
796 * push measures without having to update them too often.
797 */
798 frqp = &stktable_data_cast(ptr, std_t_frqp);
799 frqp->curr_tick = now_ms;
800 frqp->prev_ctr = 0;
801 frqp->curr_ctr = value;
802 break;
803 }
Willy Tarreau654694e2012-06-07 01:03:16 +0200804 }
805 break;
806
Willy Tarreaudec98142012-06-06 23:37:08 +0200807 default:
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100808 appctx->ctx.cli.msg = "Unknown action\n";
809 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaudec98142012-06-06 23:37:08 +0200810 break;
Simon Horman121f3052011-06-15 15:18:46 +0900811 }
Simon Horman121f3052011-06-15 15:18:46 +0900812}
813
Willy Tarreau654694e2012-06-07 01:03:16 +0200814static void stats_sock_table_data_request(struct stream_interface *si, char **args, int action)
Simon Hormand5b9fd92011-06-15 15:18:48 +0900815{
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100816 struct appctx *appctx = __objt_appctx(si->end);
817
Willy Tarreau04b3a192013-04-13 09:41:37 +0200818 if (action != STAT_CLI_O_TAB && action != STAT_CLI_O_CLR) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100819 appctx->ctx.cli.msg = "content-based lookup is only supported with the \"show\" and \"clear\" actions";
820 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau654694e2012-06-07 01:03:16 +0200821 return;
822 }
823
Simon Hormand5b9fd92011-06-15 15:18:48 +0900824 /* condition on stored data value */
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100825 appctx->ctx.table.data_type = stktable_get_data_type(args[3] + 5);
826 if (appctx->ctx.table.data_type < 0) {
827 appctx->ctx.cli.msg = "Unknown data type\n";
828 appctx->st0 = STAT_CLI_PRINT;
Simon Hormand5b9fd92011-06-15 15:18:48 +0900829 return;
830 }
831
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100832 if (!((struct proxy *)appctx->ctx.table.target)->table.data_ofs[appctx->ctx.table.data_type]) {
833 appctx->ctx.cli.msg = "Data type not stored in this table\n";
834 appctx->st0 = STAT_CLI_PRINT;
Simon Hormand5b9fd92011-06-15 15:18:48 +0900835 return;
836 }
837
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100838 appctx->ctx.table.data_op = get_std_op(args[4]);
839 if (appctx->ctx.table.data_op < 0) {
840 appctx->ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
841 appctx->st0 = STAT_CLI_PRINT;
Simon Hormand5b9fd92011-06-15 15:18:48 +0900842 return;
843 }
844
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100845 if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &appctx->ctx.table.value) != 0) {
846 appctx->ctx.cli.msg = "Require a valid integer value to compare against\n";
847 appctx->st0 = STAT_CLI_PRINT;
Simon Hormand5b9fd92011-06-15 15:18:48 +0900848 return;
849 }
850}
851
Willy Tarreaudec98142012-06-06 23:37:08 +0200852static void stats_sock_table_request(struct stream_interface *si, char **args, int action)
Simon Hormand5b9fd92011-06-15 15:18:48 +0900853{
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100854 struct appctx *appctx = __objt_appctx(si->end);
855
856 appctx->ctx.table.data_type = -1;
857 appctx->st2 = STAT_ST_INIT;
858 appctx->ctx.table.target = NULL;
859 appctx->ctx.table.proxy = NULL;
860 appctx->ctx.table.entry = NULL;
861 appctx->st0 = action;
Simon Hormand5b9fd92011-06-15 15:18:48 +0900862
863 if (*args[2]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100864 appctx->ctx.table.target = find_stktable(args[2]);
865 if (!appctx->ctx.table.target) {
866 appctx->ctx.cli.msg = "No such table\n";
867 appctx->st0 = STAT_CLI_PRINT;
Simon Hormand5b9fd92011-06-15 15:18:48 +0900868 return;
869 }
870 }
871 else {
Willy Tarreaudec98142012-06-06 23:37:08 +0200872 if (action != STAT_CLI_O_TAB)
Simon Hormand5b9fd92011-06-15 15:18:48 +0900873 goto err_args;
874 return;
875 }
876
877 if (strcmp(args[3], "key") == 0)
Willy Tarreaudec98142012-06-06 23:37:08 +0200878 stats_sock_table_key_request(si, args, action);
Simon Hormanc88b8872011-06-15 15:18:49 +0900879 else if (strncmp(args[3], "data.", 5) == 0)
Willy Tarreau654694e2012-06-07 01:03:16 +0200880 stats_sock_table_data_request(si, args, action);
Simon Hormanc88b8872011-06-15 15:18:49 +0900881 else if (*args[3])
Simon Hormand5b9fd92011-06-15 15:18:48 +0900882 goto err_args;
883
884 return;
885
886err_args:
Willy Tarreaudec98142012-06-06 23:37:08 +0200887 switch (action) {
888 case STAT_CLI_O_TAB:
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100889 appctx->ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
Willy Tarreaudec98142012-06-06 23:37:08 +0200890 break;
891 case STAT_CLI_O_CLR:
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100892 appctx->ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
Willy Tarreaudec98142012-06-06 23:37:08 +0200893 break;
894 default:
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100895 appctx->ctx.cli.msg = "Unknown action\n";
Willy Tarreaudec98142012-06-06 23:37:08 +0200896 break;
897 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100898 appctx->st0 = STAT_CLI_PRINT;
Simon Hormand5b9fd92011-06-15 15:18:48 +0900899}
900
Willy Tarreau532a4502011-09-07 22:37:44 +0200901/* Expects to find a frontend named <arg> and returns it, otherwise displays various
Willy Tarreau87b09662015-04-03 00:22:06 +0200902 * adequate error messages and returns NULL. This function also expects the stream
Willy Tarreau532a4502011-09-07 22:37:44 +0200903 * level to be admin.
904 */
Willy Tarreau87b09662015-04-03 00:22:06 +0200905static struct proxy *expect_frontend_admin(struct stream *s, struct stream_interface *si, const char *arg)
Willy Tarreau532a4502011-09-07 22:37:44 +0200906{
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100907 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreau532a4502011-09-07 22:37:44 +0200908 struct proxy *px;
909
Willy Tarreaud0d8da92015-04-04 02:10:38 +0200910 if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100911 appctx->ctx.cli.msg = stats_permission_denied_msg;
912 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +0200913 return NULL;
914 }
915
916 if (!*arg) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100917 appctx->ctx.cli.msg = "A frontend name is expected.\n";
918 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +0200919 return NULL;
920 }
921
922 px = findproxy(arg, PR_CAP_FE);
923 if (!px) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100924 appctx->ctx.cli.msg = "No such frontend.\n";
925 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +0200926 return NULL;
927 }
928 return px;
929}
930
Willy Tarreaud52c41e2011-09-07 23:41:01 +0200931/* Expects to find a backend and a server in <arg> under the form <backend>/<server>,
932 * and returns the pointer to the server. Otherwise, display adequate error messages
Willy Tarreau87b09662015-04-03 00:22:06 +0200933 * and returns NULL. This function also expects the stream level to be admin. Note:
Willy Tarreaud52c41e2011-09-07 23:41:01 +0200934 * the <arg> is modified to remove the '/'.
935 */
Willy Tarreau87b09662015-04-03 00:22:06 +0200936static struct server *expect_server_admin(struct stream *s, struct stream_interface *si, char *arg)
Willy Tarreaud52c41e2011-09-07 23:41:01 +0200937{
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100938 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreaud52c41e2011-09-07 23:41:01 +0200939 struct proxy *px;
940 struct server *sv;
941 char *line;
942
Willy Tarreaud0d8da92015-04-04 02:10:38 +0200943 if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100944 appctx->ctx.cli.msg = stats_permission_denied_msg;
945 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaud52c41e2011-09-07 23:41:01 +0200946 return NULL;
947 }
948
949 /* split "backend/server" and make <line> point to server */
950 for (line = arg; *line; line++)
951 if (*line == '/') {
952 *line++ = '\0';
953 break;
954 }
955
956 if (!*line || !*arg) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100957 appctx->ctx.cli.msg = "Require 'backend/server'.\n";
958 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaud52c41e2011-09-07 23:41:01 +0200959 return NULL;
960 }
961
962 if (!get_backend_server(arg, line, &px, &sv)) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100963 appctx->ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
964 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaud52c41e2011-09-07 23:41:01 +0200965 return NULL;
966 }
967
968 if (px->state == PR_STSTOPPED) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +0100969 appctx->ctx.cli.msg = "Proxy is disabled.\n";
970 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaud52c41e2011-09-07 23:41:01 +0200971 return NULL;
972 }
973
974 return sv;
975}
976
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100977/* This function is used with map and acl management. It permits to browse
978 * each reference. The variable <getnext> must contain the current node,
979 * <end> point to the root node and the <flags> permit to filter required
980 * nodes.
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +0100981 */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100982static inline
983struct pat_ref *pat_list_get_next(struct pat_ref *getnext, struct list *end,
984 unsigned int flags)
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +0100985{
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100986 struct pat_ref *ref = getnext;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +0100987
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +0100988 while (1) {
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +0100989
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100990 /* Get next list entry. */
991 ref = LIST_NEXT(&ref->list, struct pat_ref *, list);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +0100992
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100993 /* If the entry is the last of the list, return NULL. */
994 if (&ref->list == end)
995 return NULL;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +0100996
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100997 /* If the entry match the flag, return it. */
998 if (ref->flags & flags)
999 return ref;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001000 }
1001}
1002
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01001003static inline
1004struct pat_ref *pat_ref_lookup_ref(const char *reference)
1005{
1006 int id;
1007 char *error;
1008
1009 /* If the reference starts by a '#', this is numeric id. */
1010 if (reference[0] == '#') {
1011 /* Try to convert the numeric id. If the conversion fails, the lookup fails. */
1012 id = strtol(reference + 1, &error, 10);
1013 if (*error != '\0')
1014 return NULL;
1015
1016 /* Perform the unique id lookup. */
1017 return pat_ref_lookupid(id);
1018 }
1019
1020 /* Perform the string lookup. */
1021 return pat_ref_lookup(reference);
1022}
1023
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001024/* This function is used with map and acl management. It permits to browse
1025 * each reference.
1026 */
1027static inline
1028struct pattern_expr *pat_expr_get_next(struct pattern_expr *getnext, struct list *end)
1029{
1030 struct pattern_expr *expr;
Thierry FOURNIERc5959fd2014-01-20 14:29:33 +01001031 expr = LIST_NEXT(&getnext->list, struct pattern_expr *, list);
1032 if (&expr->list == end)
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001033 return NULL;
1034 return expr;
1035}
1036
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02001037/* Processes the stats interpreter on the statistics socket. This function is
Willy Tarreauf5a885f2009-10-04 14:22:18 +02001038 * called from an applet running in a stream interface. The function returns 1
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001039 * if the request was understood, otherwise zero. It sets appctx->st0 to a value
Willy Tarreauea1f5fe2009-10-11 23:12:51 +02001040 * designating the function which will have to process the request, which can
1041 * also be the print function to display the return message set into cli.msg.
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001042 */
Simon Horman9bd2c732011-06-15 15:18:44 +09001043static int stats_sock_parse_request(struct stream_interface *si, char *line)
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001044{
Willy Tarreau87b09662015-04-03 00:22:06 +02001045 struct stream *s = si_strm(si);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001046 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001047 char *args[MAX_STATS_ARGS + 1];
1048 int arg;
Thierry FOURNIER48bcfda2013-12-10 18:54:58 +01001049 int i, j;
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001050
1051 while (isspace((unsigned char)*line))
1052 line++;
1053
1054 arg = 0;
1055 args[arg] = line;
1056
1057 while (*line && arg < MAX_STATS_ARGS) {
Thierry FOURNIER48bcfda2013-12-10 18:54:58 +01001058 if (*line == '\\') {
1059 line++;
1060 if (*line == '\0')
1061 break;
1062 }
1063 else if (isspace((unsigned char)*line)) {
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001064 *line++ = '\0';
1065
1066 while (isspace((unsigned char)*line))
1067 line++;
1068
1069 args[++arg] = line;
1070 continue;
1071 }
1072
1073 line++;
1074 }
1075
1076 while (++arg <= MAX_STATS_ARGS)
1077 args[arg] = line;
1078
Thierry FOURNIER48bcfda2013-12-10 18:54:58 +01001079 /* remove \ */
1080 arg = 0;
1081 while (*args[arg] != '\0') {
1082 j = 0;
1083 for (i=0; args[arg][i] != '\0'; i++) {
1084 if (args[arg][i] == '\\')
1085 continue;
1086 args[arg][j] = args[arg][i];
1087 j++;
1088 }
1089 args[arg][j] = '\0';
1090 arg++;
1091 }
1092
Willy Tarreau6bcb95d2015-05-04 18:07:56 +02001093 appctx->ctx.stats.scope_str = 0;
1094 appctx->ctx.stats.scope_len = 0;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001095 appctx->ctx.stats.flags = 0;
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001096 if (strcmp(args[0], "show") == 0) {
1097 if (strcmp(args[1], "stat") == 0) {
1098 if (*args[2] && *args[3] && *args[4]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001099 appctx->ctx.stats.flags |= STAT_BOUND;
1100 appctx->ctx.stats.iid = atoi(args[2]);
1101 appctx->ctx.stats.type = atoi(args[3]);
1102 appctx->ctx.stats.sid = atoi(args[4]);
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001103 }
1104
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001105 appctx->st2 = STAT_ST_INIT;
1106 appctx->st0 = STAT_CLI_O_STAT; // stats_dump_stat_to_buffer
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001107 }
1108 else if (strcmp(args[1], "info") == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001109 appctx->st2 = STAT_ST_INIT;
1110 appctx->st0 = STAT_CLI_O_INFO; // stats_dump_info_to_buffer
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001111 }
Willy Tarreau12833bb2014-01-28 16:49:56 +01001112 else if (strcmp(args[1], "pools") == 0) {
1113 appctx->st2 = STAT_ST_INIT;
1114 appctx->st0 = STAT_CLI_O_POOLS; // stats_dump_pools_to_buffer
1115 }
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001116 else if (strcmp(args[1], "sess") == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001117 appctx->st2 = STAT_ST_INIT;
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001118 if (strm_li(s)->bind_conf->level < ACCESS_LVL_OPER) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001119 appctx->ctx.cli.msg = stats_permission_denied_msg;
1120 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau6162db22009-10-10 17:13:00 +02001121 return 1;
1122 }
Willy Tarreau76153662012-11-26 01:16:39 +01001123 if (*args[2] && strcmp(args[2], "all") == 0)
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001124 appctx->ctx.sess.target = (void *)-1;
Willy Tarreau76153662012-11-26 01:16:39 +01001125 else if (*args[2])
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001126 appctx->ctx.sess.target = (void *)strtoul(args[2], NULL, 0);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01001127 else
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001128 appctx->ctx.sess.target = NULL;
Willy Tarreau87b09662015-04-03 00:22:06 +02001129 appctx->ctx.sess.section = 0; /* start with stream status */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001130 appctx->ctx.sess.pos = 0;
1131 appctx->st0 = STAT_CLI_O_SESS; // stats_dump_sess_to_buffer
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001132 }
1133 else if (strcmp(args[1], "errors") == 0) {
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001134 if (strm_li(s)->bind_conf->level < ACCESS_LVL_OPER) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001135 appctx->ctx.cli.msg = stats_permission_denied_msg;
1136 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau6162db22009-10-10 17:13:00 +02001137 return 1;
1138 }
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001139 if (*args[2])
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001140 appctx->ctx.errors.iid = atoi(args[2]);
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001141 else
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001142 appctx->ctx.errors.iid = -1;
1143 appctx->ctx.errors.px = NULL;
1144 appctx->st2 = STAT_ST_INIT;
1145 appctx->st0 = STAT_CLI_O_ERR; // stats_dump_errors_to_buffer
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001146 }
Willy Tarreau69f58c82010-07-12 17:55:33 +02001147 else if (strcmp(args[1], "table") == 0) {
Willy Tarreaudec98142012-06-06 23:37:08 +02001148 stats_sock_table_request(si, args, STAT_CLI_O_TAB);
Willy Tarreau69f58c82010-07-12 17:55:33 +02001149 }
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001150 else if (strcmp(args[1], "map") == 0 ||
1151 strcmp(args[1], "acl") == 0) {
1152
1153 /* Set ACL or MAP flags. */
1154 if (args[1][0] == 'm')
1155 appctx->ctx.map.display_flags = PAT_REF_MAP;
1156 else
1157 appctx->ctx.map.display_flags = PAT_REF_ACL;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001158
1159 /* no parameter: display all map avalaible */
1160 if (!*args[2]) {
1161 appctx->st2 = STAT_ST_INIT;
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001162 appctx->st0 = STAT_CLI_O_PATS;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001163 return 1;
1164 }
1165
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001166 /* lookup into the refs and check the map flag */
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01001167 appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001168 if (!appctx->ctx.map.ref ||
1169 !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
1170 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001171 appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001172 else
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001173 appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001174 appctx->st0 = STAT_CLI_PRINT;
1175 return 1;
1176 }
1177 appctx->st2 = STAT_ST_INIT;
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001178 appctx->st0 = STAT_CLI_O_PAT;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001179 }
Aman Guptaceafb4a2012-04-02 18:57:54 -07001180 else { /* neither "stat" nor "info" nor "sess" nor "errors" nor "table" */
Willy Tarreau5ca791d2009-08-16 19:06:42 +02001181 return 0;
1182 }
1183 }
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +02001184 else if (strcmp(args[0], "clear") == 0) {
1185 if (strcmp(args[1], "counters") == 0) {
1186 struct proxy *px;
1187 struct server *sv;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02001188 struct listener *li;
Willy Tarreau2f6bf2b2009-10-10 15:26:26 +02001189 int clrall = 0;
1190
1191 if (strcmp(args[2], "all") == 0)
1192 clrall = 1;
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +02001193
Willy Tarreau6162db22009-10-10 17:13:00 +02001194 /* check permissions */
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001195 if (strm_li(s)->bind_conf->level < ACCESS_LVL_OPER ||
1196 (clrall && strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN)) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001197 appctx->ctx.cli.msg = stats_permission_denied_msg;
1198 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau6162db22009-10-10 17:13:00 +02001199 return 1;
1200 }
1201
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +02001202 for (px = proxy; px; px = px->next) {
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01001203 if (clrall) {
1204 memset(&px->be_counters, 0, sizeof(px->be_counters));
1205 memset(&px->fe_counters, 0, sizeof(px->fe_counters));
1206 }
Willy Tarreau2f6bf2b2009-10-10 15:26:26 +02001207 else {
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01001208 px->be_counters.conn_max = 0;
1209 px->be_counters.p.http.rps_max = 0;
1210 px->be_counters.sps_max = 0;
1211 px->be_counters.cps_max = 0;
1212 px->be_counters.nbpend_max = 0;
1213
1214 px->fe_counters.conn_max = 0;
1215 px->fe_counters.p.http.rps_max = 0;
1216 px->fe_counters.sps_max = 0;
1217 px->fe_counters.cps_max = 0;
1218 px->fe_counters.nbpend_max = 0;
Willy Tarreau2f6bf2b2009-10-10 15:26:26 +02001219 }
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +02001220
1221 for (sv = px->srv; sv; sv = sv->next)
Willy Tarreau2f6bf2b2009-10-10 15:26:26 +02001222 if (clrall)
1223 memset(&sv->counters, 0, sizeof(sv->counters));
1224 else {
1225 sv->counters.cur_sess_max = 0;
1226 sv->counters.nbpend_max = 0;
1227 sv->counters.sps_max = 0;
1228 }
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02001229
Willy Tarreaua7944ad2012-09-26 21:03:11 +02001230 list_for_each_entry(li, &px->conf.listeners, by_fe)
Willy Tarreau2f6bf2b2009-10-10 15:26:26 +02001231 if (li->counters) {
1232 if (clrall)
1233 memset(li->counters, 0, sizeof(*li->counters));
1234 else
1235 li->counters->conn_max = 0;
1236 }
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +02001237 }
1238
Willy Tarreau81c25d02011-09-07 15:17:21 +02001239 global.cps_max = 0;
Willy Tarreau93e7c002013-10-07 18:51:07 +02001240 global.sps_max = 0;
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +02001241 return 1;
1242 }
Willy Tarreau88ee3972010-07-13 13:48:00 +02001243 else if (strcmp(args[1], "table") == 0) {
Willy Tarreaudec98142012-06-06 23:37:08 +02001244 stats_sock_table_request(si, args, STAT_CLI_O_CLR);
Willy Tarreau88ee3972010-07-13 13:48:00 +02001245 /* end of processing */
1246 return 1;
1247 }
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001248 else if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
1249 /* Set ACL or MAP flags. */
1250 if (args[1][0] == 'm')
1251 appctx->ctx.map.display_flags = PAT_REF_MAP;
1252 else
1253 appctx->ctx.map.display_flags = PAT_REF_ACL;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001254
1255 /* no parameter */
1256 if (!*args[2]) {
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001257 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
1258 appctx->ctx.cli.msg = "Missing map identifier.\n";
1259 else
1260 appctx->ctx.cli.msg = "Missing ACL identifier.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001261 appctx->st0 = STAT_CLI_PRINT;
1262 return 1;
1263 }
1264
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001265 /* lookup into the refs and check the map flag */
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01001266 appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001267 if (!appctx->ctx.map.ref ||
1268 !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
1269 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001270 appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001271 else
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001272 appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001273 appctx->st0 = STAT_CLI_PRINT;
1274 return 1;
1275 }
1276
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001277 /* Clear all. */
1278 pat_ref_prune(appctx->ctx.map.ref);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001279
1280 /* return response */
Thierry FOURNIER07e78c52014-12-18 15:28:01 +01001281 appctx->st0 = STAT_CLI_PROMPT;
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001282 return 1;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001283 }
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +02001284 else {
Willy Tarreau88ee3972010-07-13 13:48:00 +02001285 /* unknown "clear" argument */
Krzysztof Piotr Oledzki719e7262009-10-04 15:02:46 +02001286 return 0;
1287 }
1288 }
Willy Tarreau38338fa2009-10-10 18:37:29 +02001289 else if (strcmp(args[0], "get") == 0) {
1290 if (strcmp(args[1], "weight") == 0) {
1291 struct proxy *px;
1292 struct server *sv;
1293
1294 /* split "backend/server" and make <line> point to server */
1295 for (line = args[2]; *line; line++)
1296 if (*line == '/') {
1297 *line++ = '\0';
1298 break;
1299 }
1300
1301 if (!*line) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001302 appctx->ctx.cli.msg = "Require 'backend/server'.\n";
1303 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau38338fa2009-10-10 18:37:29 +02001304 return 1;
1305 }
1306
1307 if (!get_backend_server(args[2], line, &px, &sv)) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001308 appctx->ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
1309 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau38338fa2009-10-10 18:37:29 +02001310 return 1;
1311 }
1312
1313 /* return server's effective weight at the moment */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01001314 snprintf(trash.str, trash.size, "%d (initial %d)\n", sv->uweight, sv->iweight);
Willy Tarreaubc18da12015-03-13 14:00:47 +01001315 if (bi_putstr(si_ic(si), trash.str) == -1)
Willy Tarreaufe127932015-04-21 19:23:39 +02001316 si_applet_cant_put(si);
Willy Tarreaubc18da12015-03-13 14:00:47 +01001317
Willy Tarreau38338fa2009-10-10 18:37:29 +02001318 return 1;
1319 }
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001320 else if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
1321 /* Set flags. */
1322 if (args[1][0] == 'm')
1323 appctx->ctx.map.display_flags = PAT_REF_MAP;
1324 else
1325 appctx->ctx.map.display_flags = PAT_REF_ACL;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001326
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001327 /* No parameter. */
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001328 if (!*args[2] || !*args[3]) {
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001329 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
1330 appctx->ctx.cli.msg = "Missing map identifier and/or key.\n";
1331 else
1332 appctx->ctx.cli.msg = "Missing ACL identifier and/or key.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001333 appctx->st0 = STAT_CLI_PRINT;
1334 return 1;
1335 }
1336
1337 /* lookup into the maps */
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01001338 appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001339 if (!appctx->ctx.map.ref) {
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001340 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001341 appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001342 else
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001343 appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001344 appctx->st0 = STAT_CLI_PRINT;
1345 return 1;
1346 }
1347
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001348 /* copy input string. The string must be allocated because
1349 * it may be used over multiple iterations. It's released
1350 * at the end and upon abort anyway.
1351 */
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001352 appctx->ctx.map.chunk.len = strlen(args[3]);
1353 appctx->ctx.map.chunk.size = appctx->ctx.map.chunk.len + 1;
1354 appctx->ctx.map.chunk.str = strdup(args[3]);
1355 if (!appctx->ctx.map.chunk.str) {
1356 appctx->ctx.cli.msg = "Out of memory error.\n";
1357 appctx->st0 = STAT_CLI_PRINT;
1358 return 1;
1359 }
1360
1361 /* prepare response */
1362 appctx->st2 = STAT_ST_INIT;
1363 appctx->st0 = STAT_CLI_O_MLOOK;
1364 }
Willy Tarreau38338fa2009-10-10 18:37:29 +02001365 else { /* not "get weight" */
1366 return 0;
1367 }
1368 }
Willy Tarreau4483d432009-10-10 19:30:08 +02001369 else if (strcmp(args[0], "set") == 0) {
1370 if (strcmp(args[1], "weight") == 0) {
Willy Tarreau4483d432009-10-10 19:30:08 +02001371 struct server *sv;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001372 const char *warning;
Willy Tarreau4483d432009-10-10 19:30:08 +02001373
Willy Tarreaud52c41e2011-09-07 23:41:01 +02001374 sv = expect_server_admin(s, si, args[2]);
1375 if (!sv)
Willy Tarreau4483d432009-10-10 19:30:08 +02001376 return 1;
Willy Tarreau4483d432009-10-10 19:30:08 +02001377
Simon Horman7d09b9a2013-02-12 10:45:51 +09001378 warning = server_parse_weight_change_request(sv, args[3]);
1379 if (warning) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001380 appctx->ctx.cli.msg = warning;
1381 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau4483d432009-10-10 19:30:08 +02001382 }
Willy Tarreau4483d432009-10-10 19:30:08 +02001383 return 1;
1384 }
Willy Tarreau2a4b70f2014-05-22 18:42:35 +02001385 else if (strcmp(args[1], "server") == 0) {
1386 struct server *sv;
1387 const char *warning;
1388
1389 sv = expect_server_admin(s, si, args[2]);
1390 if (!sv)
1391 return 1;
1392
1393 if (strcmp(args[3], "weight") == 0) {
1394 warning = server_parse_weight_change_request(sv, args[4]);
1395 if (warning) {
1396 appctx->ctx.cli.msg = warning;
1397 appctx->st0 = STAT_CLI_PRINT;
1398 }
1399 }
1400 else if (strcmp(args[3], "state") == 0) {
1401 if (strcmp(args[4], "ready") == 0)
1402 srv_adm_set_ready(sv);
1403 else if (strcmp(args[4], "drain") == 0)
1404 srv_adm_set_drain(sv);
1405 else if (strcmp(args[4], "maint") == 0)
1406 srv_adm_set_maint(sv);
1407 else {
1408 appctx->ctx.cli.msg = "'set server <srv> state' expects 'ready', 'drain' and 'maint'.\n";
1409 appctx->st0 = STAT_CLI_PRINT;
1410 }
1411 }
1412 else if (strcmp(args[3], "health") == 0) {
1413 if (sv->track) {
1414 appctx->ctx.cli.msg = "cannot change health on a tracking server.\n";
1415 appctx->st0 = STAT_CLI_PRINT;
1416 }
1417 else if (strcmp(args[4], "up") == 0) {
1418 sv->check.health = sv->check.rise + sv->check.fall - 1;
1419 srv_set_running(sv, "changed from CLI");
1420 }
1421 else if (strcmp(args[4], "stopping") == 0) {
1422 sv->check.health = sv->check.rise + sv->check.fall - 1;
1423 srv_set_stopping(sv, "changed from CLI");
1424 }
1425 else if (strcmp(args[4], "down") == 0) {
1426 sv->check.health = 0;
1427 srv_set_stopped(sv, "changed from CLI");
1428 }
1429 else {
1430 appctx->ctx.cli.msg = "'set server <srv> health' expects 'up', 'stopping', or 'down'.\n";
1431 appctx->st0 = STAT_CLI_PRINT;
1432 }
1433 }
1434 else if (strcmp(args[3], "agent") == 0) {
1435 if (!(sv->agent.state & CHK_ST_ENABLED)) {
1436 appctx->ctx.cli.msg = "agent checks are not enabled on this server.\n";
1437 appctx->st0 = STAT_CLI_PRINT;
1438 }
1439 else if (strcmp(args[4], "up") == 0) {
1440 sv->agent.health = sv->agent.rise + sv->agent.fall - 1;
1441 srv_set_running(sv, "changed from CLI");
1442 }
1443 else if (strcmp(args[4], "down") == 0) {
1444 sv->agent.health = 0;
1445 srv_set_stopped(sv, "changed from CLI");
1446 }
1447 else {
1448 appctx->ctx.cli.msg = "'set server <srv> agent' expects 'up' or 'down'.\n";
1449 appctx->st0 = STAT_CLI_PRINT;
1450 }
1451 }
1452 else {
1453 appctx->ctx.cli.msg = "'set server <srv>' only supports 'agent', 'health', 'state' and 'weight'.\n";
1454 appctx->st0 = STAT_CLI_PRINT;
1455 }
1456 return 1;
1457 }
Willy Tarreau7aabd112010-01-26 10:59:06 +01001458 else if (strcmp(args[1], "timeout") == 0) {
1459 if (strcmp(args[2], "cli") == 0) {
1460 unsigned timeout;
1461 const char *res;
1462
1463 if (!*args[3]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001464 appctx->ctx.cli.msg = "Expects an integer value.\n";
1465 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau7aabd112010-01-26 10:59:06 +01001466 return 1;
1467 }
1468
1469 res = parse_time_err(args[3], &timeout, TIME_UNIT_S);
1470 if (res || timeout < 1) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001471 appctx->ctx.cli.msg = "Invalid timeout value.\n";
1472 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau7aabd112010-01-26 10:59:06 +01001473 return 1;
1474 }
1475
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01001476 s->req.rto = s->res.wto = 1 + MS_TO_TICKS(timeout*1000);
Willy Tarreau7aabd112010-01-26 10:59:06 +01001477 return 1;
1478 }
1479 else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001480 appctx->ctx.cli.msg = "'set timeout' only supports 'cli'.\n";
1481 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau7aabd112010-01-26 10:59:06 +01001482 return 1;
1483 }
1484 }
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001485 else if (strcmp(args[1], "maxconn") == 0) {
1486 if (strcmp(args[2], "frontend") == 0) {
1487 struct proxy *px;
1488 struct listener *l;
1489 int v;
1490
Willy Tarreau532a4502011-09-07 22:37:44 +02001491 px = expect_frontend_admin(s, si, args[3]);
1492 if (!px)
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001493 return 1;
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001494
1495 if (!*args[4]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001496 appctx->ctx.cli.msg = "Integer value expected.\n";
1497 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001498 return 1;
1499 }
1500
1501 v = atoi(args[4]);
Willy Tarreau3c7a79d2012-09-26 21:07:15 +02001502 if (v < 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001503 appctx->ctx.cli.msg = "Value out of range.\n";
1504 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001505 return 1;
1506 }
1507
1508 /* OK, the value is fine, so we assign it to the proxy and to all of
1509 * its listeners. The blocked ones will be dequeued.
1510 */
1511 px->maxconn = v;
Willy Tarreaua7944ad2012-09-26 21:03:11 +02001512 list_for_each_entry(l, &px->conf.listeners, by_fe) {
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001513 l->maxconn = v;
1514 if (l->state == LI_FULL)
1515 resume_listener(l);
1516 }
1517
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001518 if (px->maxconn > px->feconn && !LIST_ISEMPTY(&strm_fe(s)->listener_queue))
1519 dequeue_all_listeners(&strm_fe(s)->listener_queue);
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001520
1521 return 1;
1522 }
Willy Tarreau91886b62011-09-07 14:38:31 +02001523 else if (strcmp(args[2], "global") == 0) {
1524 int v;
1525
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001526 if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001527 appctx->ctx.cli.msg = stats_permission_denied_msg;
1528 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau91886b62011-09-07 14:38:31 +02001529 return 1;
1530 }
1531
1532 if (!*args[3]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001533 appctx->ctx.cli.msg = "Expects an integer value.\n";
1534 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau91886b62011-09-07 14:38:31 +02001535 return 1;
1536 }
1537
1538 v = atoi(args[3]);
1539 if (v > global.hardmaxconn) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001540 appctx->ctx.cli.msg = "Value out of range.\n";
1541 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau91886b62011-09-07 14:38:31 +02001542 return 1;
1543 }
1544
1545 /* check for unlimited values */
1546 if (v <= 0)
1547 v = global.hardmaxconn;
1548
1549 global.maxconn = v;
1550
1551 /* Dequeues all of the listeners waiting for a resource */
1552 if (!LIST_ISEMPTY(&global_listener_queue))
1553 dequeue_all_listeners(&global_listener_queue);
1554
1555 return 1;
1556 }
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001557 else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001558 appctx->ctx.cli.msg = "'set maxconn' only supports 'frontend' and 'global'.\n";
1559 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau2a0f4d22011-08-02 11:49:05 +02001560 return 1;
1561 }
1562 }
Willy Tarreauf5b22872011-09-07 16:13:44 +02001563 else if (strcmp(args[1], "rate-limit") == 0) {
1564 if (strcmp(args[2], "connections") == 0) {
1565 if (strcmp(args[3], "global") == 0) {
1566 int v;
1567
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001568 if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001569 appctx->ctx.cli.msg = stats_permission_denied_msg;
1570 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreauf5b22872011-09-07 16:13:44 +02001571 return 1;
1572 }
1573
1574 if (!*args[4]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001575 appctx->ctx.cli.msg = "Expects an integer value.\n";
1576 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreauf5b22872011-09-07 16:13:44 +02001577 return 1;
1578 }
1579
1580 v = atoi(args[4]);
1581 if (v < 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001582 appctx->ctx.cli.msg = "Value out of range.\n";
1583 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreauf5b22872011-09-07 16:13:44 +02001584 return 1;
1585 }
1586
1587 global.cps_lim = v;
1588
1589 /* Dequeues all of the listeners waiting for a resource */
1590 if (!LIST_ISEMPTY(&global_listener_queue))
1591 dequeue_all_listeners(&global_listener_queue);
1592
1593 return 1;
1594 }
1595 else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001596 appctx->ctx.cli.msg = "'set rate-limit connections' only supports 'global'.\n";
1597 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreauf5b22872011-09-07 16:13:44 +02001598 return 1;
1599 }
1600 }
Willy Tarreau93e7c002013-10-07 18:51:07 +02001601 else if (strcmp(args[2], "sessions") == 0) {
1602 if (strcmp(args[3], "global") == 0) {
1603 int v;
1604
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001605 if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
Willy Tarreau93e7c002013-10-07 18:51:07 +02001606 appctx->ctx.cli.msg = stats_permission_denied_msg;
1607 appctx->st0 = STAT_CLI_PRINT;
1608 return 1;
1609 }
1610
1611 if (!*args[4]) {
1612 appctx->ctx.cli.msg = "Expects an integer value.\n";
1613 appctx->st0 = STAT_CLI_PRINT;
1614 return 1;
1615 }
1616
1617 v = atoi(args[4]);
1618 if (v < 0) {
1619 appctx->ctx.cli.msg = "Value out of range.\n";
1620 appctx->st0 = STAT_CLI_PRINT;
1621 return 1;
1622 }
1623
1624 global.sps_lim = v;
1625
1626 /* Dequeues all of the listeners waiting for a resource */
1627 if (!LIST_ISEMPTY(&global_listener_queue))
1628 dequeue_all_listeners(&global_listener_queue);
1629
1630 return 1;
1631 }
1632 else {
1633 appctx->ctx.cli.msg = "'set rate-limit sessions' only supports 'global'.\n";
1634 appctx->st0 = STAT_CLI_PRINT;
1635 return 1;
1636 }
1637 }
Willy Tarreaue43d5322013-10-07 20:01:52 +02001638#ifdef USE_OPENSSL
1639 else if (strcmp(args[2], "ssl-sessions") == 0) {
1640 if (strcmp(args[3], "global") == 0) {
1641 int v;
1642
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001643 if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
Willy Tarreaue43d5322013-10-07 20:01:52 +02001644 appctx->ctx.cli.msg = stats_permission_denied_msg;
1645 appctx->st0 = STAT_CLI_PRINT;
1646 return 1;
1647 }
1648
1649 if (!*args[4]) {
1650 appctx->ctx.cli.msg = "Expects an integer value.\n";
1651 appctx->st0 = STAT_CLI_PRINT;
1652 return 1;
1653 }
1654
1655 v = atoi(args[4]);
1656 if (v < 0) {
1657 appctx->ctx.cli.msg = "Value out of range.\n";
1658 appctx->st0 = STAT_CLI_PRINT;
1659 return 1;
1660 }
1661
1662 global.ssl_lim = v;
1663
1664 /* Dequeues all of the listeners waiting for a resource */
1665 if (!LIST_ISEMPTY(&global_listener_queue))
1666 dequeue_all_listeners(&global_listener_queue);
1667
1668 return 1;
1669 }
1670 else {
1671 appctx->ctx.cli.msg = "'set rate-limit ssl-sessions' only supports 'global'.\n";
1672 appctx->st0 = STAT_CLI_PRINT;
1673 return 1;
1674 }
1675 }
1676#endif
William Lallemandd85f9172012-11-09 17:05:39 +01001677 else if (strcmp(args[2], "http-compression") == 0) {
1678 if (strcmp(args[3], "global") == 0) {
1679 int v;
1680
Willy Tarreau85d47f92012-11-21 00:29:50 +01001681 if (!*args[4]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001682 appctx->ctx.cli.msg = "Expects a maximum input byte rate in kB/s.\n";
1683 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau85d47f92012-11-21 00:29:50 +01001684 return 1;
1685 }
1686
William Lallemandd85f9172012-11-09 17:05:39 +01001687 v = atoi(args[4]);
1688 global.comp_rate_lim = v * 1024; /* Kilo to bytes. */
1689 }
1690 else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001691 appctx->ctx.cli.msg = "'set rate-limit http-compression' only supports 'global'.\n";
1692 appctx->st0 = STAT_CLI_PRINT;
William Lallemandd85f9172012-11-09 17:05:39 +01001693 return 1;
1694 }
1695 }
Willy Tarreauf5b22872011-09-07 16:13:44 +02001696 else {
Willy Tarreaue43d5322013-10-07 20:01:52 +02001697 appctx->ctx.cli.msg = "'set rate-limit' supports 'connections', 'sessions', 'ssl-sessions', and 'http-compression'.\n";
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001698 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreauf5b22872011-09-07 16:13:44 +02001699 return 1;
1700 }
1701 }
Willy Tarreau654694e2012-06-07 01:03:16 +02001702 else if (strcmp(args[1], "table") == 0) {
1703 stats_sock_table_request(si, args, STAT_CLI_O_SET);
1704 }
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001705 else if (strcmp(args[1], "map") == 0) {
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01001706 char *err;
1707
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01001708 /* Set flags. */
1709 appctx->ctx.map.display_flags = PAT_REF_MAP;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001710
1711 /* Expect three parameters: map name, key and new value. */
1712 if (!*args[2] || !*args[3] || !*args[4]) {
Thierry FOURNIERd5723432014-03-11 13:52:44 +01001713 appctx->ctx.cli.msg = "'set map' expects three parameters: map identifier, key and value.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001714 appctx->st0 = STAT_CLI_PRINT;
1715 return 1;
1716 }
1717
1718 /* Lookup the reference in the maps. */
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01001719 appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001720 if (!appctx->ctx.map.ref) {
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001721 appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001722 appctx->st0 = STAT_CLI_PRINT;
1723 return 1;
1724 }
1725
Thierry FOURNIER9356c682014-01-28 15:55:37 +01001726 /* If the entry identifier start with a '#', it is considered as
1727 * pointer id
1728 */
1729 if (args[3][0] == '#' && args[3][1] == '0' && args[3][2] == 'x') {
1730 struct pat_ref_elt *ref;
1731 long long int conv;
1732 char *error;
1733
1734 /* Convert argument to integer value. */
1735 conv = strtoll(&args[3][1], &error, 16);
1736 if (*error != '\0') {
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001737 appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
Thierry FOURNIER9356c682014-01-28 15:55:37 +01001738 appctx->st0 = STAT_CLI_PRINT;
1739 return 1;
1740 }
1741
1742 /* Convert and check integer to pointer. */
1743 ref = (struct pat_ref_elt *)(long)conv;
1744 if ((long long int)(long)ref != conv) {
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01001745 appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
Thierry FOURNIER9356c682014-01-28 15:55:37 +01001746 appctx->st0 = STAT_CLI_PRINT;
1747 return 1;
1748 }
1749
1750 /* Try to delete the entry. */
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01001751 err = NULL;
1752 if (!pat_ref_set_by_id(appctx->ctx.map.ref, ref, args[4], &err)) {
1753 if (err)
1754 memprintf(&err, "%s.\n", err);
1755 appctx->ctx.cli.err = err;
1756 appctx->st0 = STAT_CLI_PRINT_FREE;
Thierry FOURNIER9356c682014-01-28 15:55:37 +01001757 return 1;
1758 }
1759 }
1760 else {
1761 /* Else, use the entry identifier as pattern
1762 * string, and update the value.
1763 */
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01001764 err = NULL;
1765 if (!pat_ref_set(appctx->ctx.map.ref, args[3], args[4], &err)) {
1766 if (err)
1767 memprintf(&err, "%s.\n", err);
1768 appctx->ctx.cli.err = err;
1769 appctx->st0 = STAT_CLI_PRINT_FREE;
Thierry FOURNIER9356c682014-01-28 15:55:37 +01001770 return 1;
1771 }
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001772 }
1773
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001774 /* The set is done, send message. */
Thierry FOURNIER07e78c52014-12-18 15:28:01 +01001775 appctx->st0 = STAT_CLI_PROMPT;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01001776 return 1;
1777 }
Emeric Brun4147b2e2014-06-16 18:36:30 +02001778#ifdef USE_OPENSSL
1779 else if (strcmp(args[1], "ssl") == 0) {
1780 if (strcmp(args[2], "ocsp-response") == 0) {
Lukas Tribuse4e30f72014-12-09 16:32:51 +01001781#if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
Emeric Brun4147b2e2014-06-16 18:36:30 +02001782 char *err = NULL;
1783
Emeric Brunaf4ef742014-06-19 14:10:45 +02001784 /* Expect one parameter: the new response in base64 encoding */
Emeric Brun4147b2e2014-06-16 18:36:30 +02001785 if (!*args[3]) {
1786 appctx->ctx.cli.msg = "'set ssl ocsp-response' expects response in base64 encoding.\n";
1787 appctx->st0 = STAT_CLI_PRINT;
1788 return 1;
1789 }
1790
1791 trash.len = base64dec(args[3], strlen(args[3]), trash.str, trash.size);
1792 if (trash.len < 0) {
1793 appctx->ctx.cli.msg = "'set ssl ocsp-response' received invalid base64 encoded response.\n";
1794 appctx->st0 = STAT_CLI_PRINT;
1795 return 1;
1796 }
1797
1798 if (ssl_sock_update_ocsp_response(&trash, &err)) {
1799 if (err) {
1800 memprintf(&err, "%s.\n", err);
1801 appctx->ctx.cli.err = err;
1802 appctx->st0 = STAT_CLI_PRINT_FREE;
1803 }
1804 return 1;
1805 }
1806 appctx->ctx.cli.msg = "OCSP Response updated!";
1807 appctx->st0 = STAT_CLI_PRINT;
1808 return 1;
1809#else
1810 appctx->ctx.cli.msg = "HAProxy was compiled against a version of OpenSSL that doesn't support OCSP stapling.\n";
1811 appctx->st0 = STAT_CLI_PRINT;
1812 return 1;
1813#endif
1814 }
1815 else {
1816 appctx->ctx.cli.msg = "'set ssl' only supports 'ocsp-response'.\n";
1817 appctx->st0 = STAT_CLI_PRINT;
1818 return 1;
1819 }
1820 }
1821#endif
Willy Tarreau7aabd112010-01-26 10:59:06 +01001822 else { /* unknown "set" parameter */
Willy Tarreau4483d432009-10-10 19:30:08 +02001823 return 0;
1824 }
1825 }
Cyril Bontécd19e512010-01-31 22:34:03 +01001826 else if (strcmp(args[0], "enable") == 0) {
Simon Horman671b6f02013-11-25 10:46:39 +09001827 if (strcmp(args[1], "agent") == 0) {
1828 struct server *sv;
1829
1830 sv = expect_server_admin(s, si, args[2]);
1831 if (!sv)
1832 return 1;
1833
Willy Tarreau2e10f5a2013-12-11 20:11:55 +01001834 if (!(sv->agent.state & CHK_ST_CONFIGURED)) {
1835 appctx->ctx.cli.msg = "Agent was not configured on this server, cannot enable.\n";
1836 appctx->st0 = STAT_CLI_PRINT;
1837 return 1;
1838 }
1839
1840 sv->agent.state |= CHK_ST_ENABLED;
Simon Horman671b6f02013-11-25 10:46:39 +09001841 return 1;
1842 }
Willy Tarreau9b5aecd2014-05-23 11:53:10 +02001843 else if (strcmp(args[1], "health") == 0) {
Cyril Bontécd19e512010-01-31 22:34:03 +01001844 struct server *sv;
1845
Willy Tarreaud52c41e2011-09-07 23:41:01 +02001846 sv = expect_server_admin(s, si, args[2]);
1847 if (!sv)
Cyril Bonté613f0df2011-03-03 20:49:04 +01001848 return 1;
Cyril Bonté613f0df2011-03-03 20:49:04 +01001849
Willy Tarreau9b5aecd2014-05-23 11:53:10 +02001850 if (!(sv->check.state & CHK_ST_CONFIGURED)) {
1851 appctx->ctx.cli.msg = "Health checks are not configured on this server, cannot enable.\n";
1852 appctx->st0 = STAT_CLI_PRINT;
1853 return 1;
1854 }
1855
1856 sv->check.state |= CHK_ST_ENABLED;
1857 return 1;
1858 }
1859 else if (strcmp(args[1], "server") == 0) {
1860 struct server *sv;
1861
1862 sv = expect_server_admin(s, si, args[2]);
1863 if (!sv)
1864 return 1;
1865
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001866 srv_adm_set_ready(sv);
Willy Tarreau532a4502011-09-07 22:37:44 +02001867 return 1;
1868 }
1869 else if (strcmp(args[1], "frontend") == 0) {
1870 struct proxy *px;
1871
1872 px = expect_frontend_admin(s, si, args[2]);
1873 if (!px)
1874 return 1;
1875
1876 if (px->state == PR_STSTOPPED) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001877 appctx->ctx.cli.msg = "Frontend was previously shut down, cannot enable.\n";
1878 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001879 return 1;
1880 }
1881
1882 if (px->state != PR_STPAUSED) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001883 appctx->ctx.cli.msg = "Frontend is already enabled.\n";
1884 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001885 return 1;
1886 }
1887
1888 if (!resume_proxy(px)) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001889 appctx->ctx.cli.msg = "Failed to resume frontend, check logs for precise cause (port conflict?).\n";
1890 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001891 return 1;
1892 }
Cyril Bontécd19e512010-01-31 22:34:03 +01001893 return 1;
1894 }
1895 else { /* unknown "enable" parameter */
Willy Tarreau9b5aecd2014-05-23 11:53:10 +02001896 appctx->ctx.cli.msg = "'enable' only supports 'agent', 'frontend', 'health', and 'server'.\n";
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001897 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001898 return 1;
Cyril Bontécd19e512010-01-31 22:34:03 +01001899 }
1900 }
1901 else if (strcmp(args[0], "disable") == 0) {
Simon Horman671b6f02013-11-25 10:46:39 +09001902 if (strcmp(args[1], "agent") == 0) {
1903 struct server *sv;
1904
1905 sv = expect_server_admin(s, si, args[2]);
1906 if (!sv)
1907 return 1;
1908
Willy Tarreau2e10f5a2013-12-11 20:11:55 +01001909 sv->agent.state &= ~CHK_ST_ENABLED;
Simon Horman671b6f02013-11-25 10:46:39 +09001910 return 1;
1911 }
Willy Tarreau9b5aecd2014-05-23 11:53:10 +02001912 else if (strcmp(args[1], "health") == 0) {
1913 struct server *sv;
1914
1915 sv = expect_server_admin(s, si, args[2]);
1916 if (!sv)
1917 return 1;
1918
1919 sv->check.state &= ~CHK_ST_ENABLED;
1920 return 1;
1921 }
Simon Horman671b6f02013-11-25 10:46:39 +09001922 else if (strcmp(args[1], "server") == 0) {
Cyril Bontécd19e512010-01-31 22:34:03 +01001923 struct server *sv;
1924
Willy Tarreaud52c41e2011-09-07 23:41:01 +02001925 sv = expect_server_admin(s, si, args[2]);
1926 if (!sv)
Cyril Bonté613f0df2011-03-03 20:49:04 +01001927 return 1;
Cyril Bonté613f0df2011-03-03 20:49:04 +01001928
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001929 srv_adm_set_maint(sv);
Willy Tarreau532a4502011-09-07 22:37:44 +02001930 return 1;
1931 }
1932 else if (strcmp(args[1], "frontend") == 0) {
1933 struct proxy *px;
1934
1935 px = expect_frontend_admin(s, si, args[2]);
1936 if (!px)
1937 return 1;
1938
1939 if (px->state == PR_STSTOPPED) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001940 appctx->ctx.cli.msg = "Frontend was previously shut down, cannot disable.\n";
1941 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001942 return 1;
1943 }
1944
1945 if (px->state == PR_STPAUSED) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001946 appctx->ctx.cli.msg = "Frontend is already disabled.\n";
1947 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001948 return 1;
1949 }
1950
1951 if (!pause_proxy(px)) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001952 appctx->ctx.cli.msg = "Failed to pause frontend, check logs for precise cause.\n";
1953 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001954 return 1;
1955 }
Cyril Bontécd19e512010-01-31 22:34:03 +01001956 return 1;
1957 }
1958 else { /* unknown "disable" parameter */
Willy Tarreau9b5aecd2014-05-23 11:53:10 +02001959 appctx->ctx.cli.msg = "'disable' only supports 'agent', 'frontend', 'health', and 'server'.\n";
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001960 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001961 return 1;
1962 }
1963 }
1964 else if (strcmp(args[0], "shutdown") == 0) {
1965 if (strcmp(args[1], "frontend") == 0) {
1966 struct proxy *px;
1967
1968 px = expect_frontend_admin(s, si, args[2]);
1969 if (!px)
1970 return 1;
1971
1972 if (px->state == PR_STSTOPPED) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001973 appctx->ctx.cli.msg = "Frontend was already shut down.\n";
1974 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02001975 return 1;
1976 }
1977
1978 Warning("Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
1979 px->id, px->fe_counters.cum_conn, px->be_counters.cum_conn);
1980 send_log(px, LOG_WARNING, "Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
1981 px->id, px->fe_counters.cum_conn, px->be_counters.cum_conn);
1982 stop_proxy(px);
1983 return 1;
1984 }
Willy Tarreaua295edc2011-09-07 23:21:03 +02001985 else if (strcmp(args[1], "session") == 0) {
Willy Tarreau87b09662015-04-03 00:22:06 +02001986 struct stream *sess, *ptr;
Willy Tarreaua295edc2011-09-07 23:21:03 +02001987
Willy Tarreaud0d8da92015-04-04 02:10:38 +02001988 if (strm_li(s)->bind_conf->level < ACCESS_LVL_ADMIN) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001989 appctx->ctx.cli.msg = stats_permission_denied_msg;
1990 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaua295edc2011-09-07 23:21:03 +02001991 return 1;
1992 }
1993
1994 if (!*args[2]) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01001995 appctx->ctx.cli.msg = "Session pointer expected (use 'show sess').\n";
1996 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaua295edc2011-09-07 23:21:03 +02001997 return 1;
1998 }
1999
2000 ptr = (void *)strtoul(args[2], NULL, 0);
2001
Willy Tarreau87b09662015-04-03 00:22:06 +02002002 /* first, look for the requested stream in the stream table */
2003 list_for_each_entry(sess, &streams, list) {
Willy Tarreaua295edc2011-09-07 23:21:03 +02002004 if (sess == ptr)
2005 break;
2006 }
2007
Willy Tarreau87b09662015-04-03 00:22:06 +02002008 /* do we have the stream ? */
Willy Tarreaua295edc2011-09-07 23:21:03 +02002009 if (sess != ptr) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002010 appctx->ctx.cli.msg = "No such session (use 'show sess').\n";
2011 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreaua295edc2011-09-07 23:21:03 +02002012 return 1;
2013 }
2014
Willy Tarreaue7dff022015-04-03 01:14:29 +02002015 stream_shutdown(sess, SF_ERR_KILLED);
Willy Tarreaua295edc2011-09-07 23:21:03 +02002016 return 1;
2017 }
Willy Tarreau52b2d222011-09-07 23:48:48 +02002018 else if (strcmp(args[1], "sessions") == 0) {
2019 if (strcmp(args[2], "server") == 0) {
2020 struct server *sv;
Willy Tarreau87b09662015-04-03 00:22:06 +02002021 struct stream *sess, *sess_bck;
Willy Tarreau52b2d222011-09-07 23:48:48 +02002022
2023 sv = expect_server_admin(s, si, args[3]);
2024 if (!sv)
2025 return 1;
2026
Willy Tarreau87b09662015-04-03 00:22:06 +02002027 /* kill all the stream that are on this server */
Willy Tarreau52b2d222011-09-07 23:48:48 +02002028 list_for_each_entry_safe(sess, sess_bck, &sv->actconns, by_srv)
2029 if (sess->srv_conn == sv)
Willy Tarreaue7dff022015-04-03 01:14:29 +02002030 stream_shutdown(sess, SF_ERR_KILLED);
Willy Tarreau52b2d222011-09-07 23:48:48 +02002031
2032 return 1;
2033 }
2034 else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002035 appctx->ctx.cli.msg = "'shutdown sessions' only supports 'server'.\n";
2036 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau52b2d222011-09-07 23:48:48 +02002037 return 1;
2038 }
2039 }
Willy Tarreau532a4502011-09-07 22:37:44 +02002040 else { /* unknown "disable" parameter */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002041 appctx->ctx.cli.msg = "'shutdown' only supports 'frontend', 'session' and 'sessions'.\n";
2042 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau532a4502011-09-07 22:37:44 +02002043 return 1;
Cyril Bontécd19e512010-01-31 22:34:03 +01002044 }
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002045 }
2046 else if (strcmp(args[0], "del") == 0) {
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002047 if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
2048 if (args[1][0] == 'm')
2049 appctx->ctx.map.display_flags = PAT_REF_MAP;
2050 else
2051 appctx->ctx.map.display_flags = PAT_REF_ACL;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002052
2053 /* Expect two parameters: map name and key. */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002054 if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
2055 if (!*args[2] || !*args[3]) {
2056 appctx->ctx.cli.msg = "This command expects two parameters: map identifier and key.\n";
2057 appctx->st0 = STAT_CLI_PRINT;
2058 return 1;
2059 }
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002060 }
2061
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002062 else {
2063 if (!*args[2] || !*args[3]) {
2064 appctx->ctx.cli.msg = "This command expects two parameters: ACL identifier and key.\n";
2065 appctx->st0 = STAT_CLI_PRINT;
2066 return 1;
2067 }
2068 }
2069
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002070 /* Lookup the reference in the maps. */
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01002071 appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002072 if (!appctx->ctx.map.ref ||
2073 !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01002074 appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002075 appctx->st0 = STAT_CLI_PRINT;
2076 return 1;
2077 }
2078
Thierry FOURNIER9356c682014-01-28 15:55:37 +01002079 /* If the entry identifier start with a '#', it is considered as
2080 * pointer id
2081 */
2082 if (args[3][0] == '#' && args[3][1] == '0' && args[3][2] == 'x') {
2083 struct pat_ref_elt *ref;
2084 long long int conv;
2085 char *error;
2086
2087 /* Convert argument to integer value. */
2088 conv = strtoll(&args[3][1], &error, 16);
2089 if (*error != '\0') {
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01002090 appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
Thierry FOURNIER9356c682014-01-28 15:55:37 +01002091 appctx->st0 = STAT_CLI_PRINT;
2092 return 1;
2093 }
2094
2095 /* Convert and check integer to pointer. */
2096 ref = (struct pat_ref_elt *)(long)conv;
2097 if ((long long int)(long)ref != conv) {
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01002098 appctx->ctx.cli.msg = "Malformed identifier. Please use #<id> or <file>.\n";
Thierry FOURNIER9356c682014-01-28 15:55:37 +01002099 appctx->st0 = STAT_CLI_PRINT;
2100 return 1;
2101 }
2102
2103 /* Try to delete the entry. */
2104 if (!pat_ref_delete_by_id(appctx->ctx.map.ref, ref)) {
2105 /* The entry is not found, send message. */
2106 appctx->ctx.cli.msg = "Key not found.\n";
2107 appctx->st0 = STAT_CLI_PRINT;
2108 return 1;
2109 }
2110 }
2111 else {
2112 /* Else, use the entry identifier as pattern
2113 * string and try to delete the entry.
2114 */
2115 if (!pat_ref_delete(appctx->ctx.map.ref, args[3])) {
2116 /* The entry is not found, send message. */
2117 appctx->ctx.cli.msg = "Key not found.\n";
2118 appctx->st0 = STAT_CLI_PRINT;
2119 return 1;
2120 }
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002121 }
2122
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002123 /* The deletion is done, send message. */
Thierry FOURNIER07e78c52014-12-18 15:28:01 +01002124 appctx->st0 = STAT_CLI_PROMPT;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002125 return 1;
2126 }
2127 else { /* unknown "del" parameter */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002128 appctx->ctx.cli.msg = "'del' only supports 'map' or 'acl'.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002129 appctx->st0 = STAT_CLI_PRINT;
2130 return 1;
2131 }
2132 }
2133 else if (strcmp(args[0], "add") == 0) {
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002134 if (strcmp(args[1], "map") == 0 ||
2135 strcmp(args[1], "acl") == 0) {
2136 int ret;
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01002137 char *err;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002138
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002139 /* Set flags. */
2140 if (args[1][0] == 'm')
2141 appctx->ctx.map.display_flags = PAT_REF_MAP;
2142 else
2143 appctx->ctx.map.display_flags = PAT_REF_ACL;
2144
2145 /* If the keywork is "map", we expect three parameters, if it
2146 * is "acl", we expect only two parameters
2147 */
2148 if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
2149 if (!*args[2] || !*args[3] || !*args[4]) {
2150 appctx->ctx.cli.msg = "'add map' expects three parameters: map identifier, key and value.\n";
2151 appctx->st0 = STAT_CLI_PRINT;
2152 return 1;
2153 }
2154 }
2155 else {
2156 if (!*args[2] || !*args[3]) {
2157 appctx->ctx.cli.msg = "'add acl' expects two parameters: ACL identifier and pattern.\n";
2158 appctx->st0 = STAT_CLI_PRINT;
2159 return 1;
2160 }
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002161 }
2162
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002163 /* Lookup for the reference. */
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01002164 appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002165 if (!appctx->ctx.map.ref) {
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002166 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01002167 appctx->ctx.cli.msg = "Unknown map identifier. Please use #<id> or <file>.\n";
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002168 else
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01002169 appctx->ctx.cli.msg = "Unknown ACL identifier. Please use #<id> or <file>.\n";
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002170 appctx->st0 = STAT_CLI_PRINT;
2171 return 1;
2172 }
2173
Thierry FOURNIER64c585f2014-01-29 20:02:36 +01002174 /* The command "add acl" is prohibited if the reference
2175 * use samples.
2176 */
2177 if ((appctx->ctx.map.display_flags & PAT_REF_ACL) &&
2178 (appctx->ctx.map.ref->flags & PAT_REF_SMP)) {
2179 appctx->ctx.cli.msg = "This ACL is shared with a map containing samples. "
2180 "You must use the command 'add map' to add values.\n";
2181 appctx->st0 = STAT_CLI_PRINT;
2182 return 1;
2183 }
2184
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002185 /* Add value. */
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01002186 err = NULL;
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002187 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +02002188 ret = pat_ref_add(appctx->ctx.map.ref, args[3], args[4], &err);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002189 else
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +02002190 ret = pat_ref_add(appctx->ctx.map.ref, args[3], NULL, &err);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002191 if (!ret) {
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01002192 if (err)
2193 memprintf(&err, "%s.\n", err);
2194 appctx->ctx.cli.err = err;
2195 appctx->st0 = STAT_CLI_PRINT_FREE;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002196 return 1;
2197 }
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002198
2199 /* The add is done, send message. */
Thierry FOURNIER07e78c52014-12-18 15:28:01 +01002200 appctx->st0 = STAT_CLI_PROMPT;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002201 return 1;
2202 }
2203 else { /* unknown "del" parameter */
2204 appctx->ctx.cli.msg = "'add' only supports 'map'.\n";
2205 appctx->st0 = STAT_CLI_PRINT;
2206 return 1;
2207 }
Cyril Bontécd19e512010-01-31 22:34:03 +01002208 }
2209 else { /* not "show" nor "clear" nor "get" nor "set" nor "enable" nor "disable" */
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002210 return 0;
2211 }
2212 return 1;
2213}
2214
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002215/* This I/O handler runs as an applet embedded in a stream interface. It is
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002216 * used to processes I/O from/to the stats unix socket. The system relies on a
2217 * state machine handling requests and various responses. We read a request,
2218 * then we process it and send the response, and we possibly display a prompt.
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002219 * Then we can read again. The state is stored in appctx->st0 and is one of the
2220 * STAT_CLI_* constants. appctx->st1 is used to indicate whether prompt is enabled
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002221 * or not.
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002222 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02002223static void cli_io_handler(struct appctx *appctx)
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002224{
Willy Tarreau00a37f02015-04-13 12:05:19 +02002225 struct stream_interface *si = appctx->owner;
Willy Tarreau2bb4a962014-11-28 11:11:05 +01002226 struct channel *req = si_oc(si);
2227 struct channel *res = si_ic(si);
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002228 int reql;
2229 int len;
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002230
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002231 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
2232 goto out;
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002233
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002234 while (1) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002235 if (appctx->st0 == STAT_CLI_INIT) {
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002236 /* Stats output not initialized yet */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002237 memset(&appctx->ctx.stats, 0, sizeof(appctx->ctx.stats));
2238 appctx->st0 = STAT_CLI_GETREQ;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002239 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002240 else if (appctx->st0 == STAT_CLI_END) {
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002241 /* Let's close for real now. We just close the request
2242 * side, the conditions below will complete if needed.
2243 */
Willy Tarreau73b013b2012-05-21 16:31:45 +02002244 si_shutw(si);
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002245 break;
2246 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002247 else if (appctx->st0 == STAT_CLI_GETREQ) {
Willy Tarreau4e33d862009-10-11 23:35:10 +02002248 /* ensure we have some output room left in the event we
2249 * would want to return some info right after parsing.
2250 */
Willy Tarreau4e4292b2014-11-28 12:18:45 +01002251 if (buffer_almost_full(si_ib(si))) {
Willy Tarreaufe127932015-04-21 19:23:39 +02002252 si_applet_cant_put(si);
Willy Tarreau4e33d862009-10-11 23:35:10 +02002253 break;
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01002254 }
Willy Tarreau4e33d862009-10-11 23:35:10 +02002255
Willy Tarreau2bb4a962014-11-28 11:11:05 +01002256 reql = bo_getline(si_oc(si), trash.str, trash.size);
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002257 if (reql <= 0) { /* closed or EOL not found */
2258 if (reql == 0)
2259 break;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002260 appctx->st0 = STAT_CLI_END;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002261 continue;
2262 }
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002263
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002264 /* seek for a possible semi-colon. If we find one, we
2265 * replace it with an LF and skip only this part.
2266 */
2267 for (len = 0; len < reql; len++)
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002268 if (trash.str[len] == ';') {
2269 trash.str[len] = '\n';
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002270 reql = len + 1;
2271 break;
2272 }
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002273
Willy Tarreau816fc222009-10-04 07:36:58 +02002274 /* now it is time to check that we have a full line,
2275 * remove the trailing \n and possibly \r, then cut the
2276 * line.
2277 */
2278 len = reql - 1;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002279 if (trash.str[len] != '\n') {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002280 appctx->st0 = STAT_CLI_END;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002281 continue;
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002282 }
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002283
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002284 if (len && trash.str[len-1] == '\r')
Willy Tarreau816fc222009-10-04 07:36:58 +02002285 len--;
2286
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002287 trash.str[len] = '\0';
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002288
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002289 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002290 if (len) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002291 if (strcmp(trash.str, "quit") == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002292 appctx->st0 = STAT_CLI_END;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002293 continue;
2294 }
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002295 else if (strcmp(trash.str, "prompt") == 0)
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002296 appctx->st1 = !appctx->st1;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002297 else if (strcmp(trash.str, "help") == 0 ||
2298 !stats_sock_parse_request(si, trash.str)) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002299 appctx->ctx.cli.msg = stats_sock_usage_msg;
2300 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreauea1f5fe2009-10-11 23:12:51 +02002301 }
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002302 /* NB: stats_sock_parse_request() may have put
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002303 * another STAT_CLI_O_* into appctx->st0.
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002304 */
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002305 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002306 else if (!appctx->st1) {
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002307 /* if prompt is disabled, print help on empty lines,
2308 * so that the user at least knows how to enable
2309 * prompt and find help.
2310 */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002311 appctx->ctx.cli.msg = stats_sock_usage_msg;
2312 appctx->st0 = STAT_CLI_PRINT;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002313 }
2314
2315 /* re-adjust req buffer */
Willy Tarreau2bb4a962014-11-28 11:11:05 +01002316 bo_skip(si_oc(si), reql);
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002317 req->flags |= CF_READ_DONTWAIT; /* we plan to read small requests */
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002318 }
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002319 else { /* output functions: first check if the output buffer is closed then abort */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002320 if (res->flags & (CF_SHUTR_NOW|CF_SHUTR)) {
Willy Tarreau00a37f02015-04-13 12:05:19 +02002321 cli_release_handler(appctx);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002322 appctx->st0 = STAT_CLI_END;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002323 continue;
2324 }
2325
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002326 switch (appctx->st0) {
Willy Tarreauea1f5fe2009-10-11 23:12:51 +02002327 case STAT_CLI_PRINT:
Willy Tarreau2bb4a962014-11-28 11:11:05 +01002328 if (bi_putstr(si_ic(si), appctx->ctx.cli.msg) != -1)
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002329 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002330 else
Willy Tarreaufe127932015-04-21 19:23:39 +02002331 si_applet_cant_put(si);
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002332 break;
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01002333 case STAT_CLI_PRINT_FREE:
Willy Tarreau2bb4a962014-11-28 11:11:05 +01002334 if (bi_putstr(si_ic(si), appctx->ctx.cli.err) != -1) {
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01002335 free(appctx->ctx.cli.err);
2336 appctx->st0 = STAT_CLI_PROMPT;
2337 }
Willy Tarreaubc18da12015-03-13 14:00:47 +01002338 else
Willy Tarreaufe127932015-04-21 19:23:39 +02002339 si_applet_cant_put(si);
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01002340 break;
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002341 case STAT_CLI_O_INFO:
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002342 if (stats_dump_info_to_buffer(si))
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002343 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002344 break;
2345 case STAT_CLI_O_STAT:
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002346 if (stats_dump_stat_to_buffer(si, NULL))
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002347 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002348 break;
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002349 case STAT_CLI_O_SESS:
Willy Tarreau5ec29ff2011-02-13 15:27:22 +01002350 if (stats_dump_sess_to_buffer(si))
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002351 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002352 break;
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002353 case STAT_CLI_O_ERR: /* errors dump */
Willy Tarreau5ec29ff2011-02-13 15:27:22 +01002354 if (stats_dump_errors_to_buffer(si))
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002355 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002356 break;
Willy Tarreau69f58c82010-07-12 17:55:33 +02002357 case STAT_CLI_O_TAB:
Simon Hormanc88b8872011-06-15 15:18:49 +09002358 case STAT_CLI_O_CLR:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002359 if (stats_table_request(si, appctx->st0))
2360 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreau69f58c82010-07-12 17:55:33 +02002361 break;
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002362 case STAT_CLI_O_PATS:
2363 if (stats_pats_list(si))
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002364 appctx->st0 = STAT_CLI_PROMPT;
2365 break;
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01002366 case STAT_CLI_O_PAT:
2367 if (stats_pat_list(si))
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01002368 appctx->st0 = STAT_CLI_PROMPT;
2369 break;
2370 case STAT_CLI_O_MLOOK:
2371 if (stats_map_lookup(si))
2372 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreau4efb3532014-01-29 12:13:39 +01002373 break;
Willy Tarreau12833bb2014-01-28 16:49:56 +01002374 case STAT_CLI_O_POOLS:
2375 if (stats_dump_pools_to_buffer(si))
2376 appctx->st0 = STAT_CLI_PROMPT;
2377 break;
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002378 default: /* abnormal state */
Willy Tarreau00a37f02015-04-13 12:05:19 +02002379 cli_release_handler(appctx);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002380 appctx->st0 = STAT_CLI_PROMPT;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002381 break;
2382 }
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002383
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002384 /* The post-command prompt is either LF alone or LF + '> ' in interactive mode */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002385 if (appctx->st0 == STAT_CLI_PROMPT) {
Willy Tarreau2bb4a962014-11-28 11:11:05 +01002386 if (bi_putstr(si_ic(si), appctx->st1 ? "\n> " : "\n") != -1)
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002387 appctx->st0 = STAT_CLI_GETREQ;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002388 else
Willy Tarreaufe127932015-04-21 19:23:39 +02002389 si_applet_cant_put(si);
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002390 }
2391
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002392 /* If the output functions are still there, it means they require more room. */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002393 if (appctx->st0 >= STAT_CLI_OUTPUT)
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002394 break;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002395
2396 /* Now we close the output if one of the writers did so,
2397 * or if we're not in interactive mode and the request
2398 * buffer is empty. This still allows pipelined requests
2399 * to be sent in non-interactive mode.
2400 */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002401 if ((res->flags & (CF_SHUTW|CF_SHUTW_NOW)) || (!appctx->st1 && !req->buf->o)) {
2402 appctx->st0 = STAT_CLI_END;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002403 continue;
2404 }
2405
Willy Tarreauf5a885f2009-10-04 14:22:18 +02002406 /* switch state back to GETREQ to read next requests */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002407 appctx->st0 = STAT_CLI_GETREQ;
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002408 }
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002409 }
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002410
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002411 if ((res->flags & CF_SHUTR) && (si->state == SI_ST_EST) && (appctx->st0 != STAT_CLI_GETREQ)) {
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002412 DPRINTF(stderr, "%s@%d: si to buf closed. req=%08x, res=%08x, st=%d\n",
2413 __FUNCTION__, __LINE__, req->flags, res->flags, si->state);
Aman Guptaceafb4a2012-04-02 18:57:54 -07002414 /* Other side has closed, let's abort if we have no more processing to do
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002415 * and nothing more to consume. This is comparable to a broken pipe, so
2416 * we forward the close to the request side so that it flows upstream to
2417 * the client.
2418 */
Willy Tarreau73b013b2012-05-21 16:31:45 +02002419 si_shutw(si);
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002420 }
2421
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002422 if ((req->flags & CF_SHUTW) && (si->state == SI_ST_EST) && (appctx->st0 < STAT_CLI_OUTPUT)) {
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002423 DPRINTF(stderr, "%s@%d: buf to si closed. req=%08x, res=%08x, st=%d\n",
2424 __FUNCTION__, __LINE__, req->flags, res->flags, si->state);
2425 /* We have no more processing to do, and nothing more to send, and
2426 * the client side has closed. So we'll forward this state downstream
2427 * on the response buffer.
2428 */
Willy Tarreau73b013b2012-05-21 16:31:45 +02002429 si_shutr(si);
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002430 res->flags |= CF_READ_NULL;
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002431 }
2432
Willy Tarreau828824a2015-04-19 17:20:03 +02002433 out:
Willy Tarreau02d6cfc2012-03-01 18:19:58 +01002434 DPRINTF(stderr, "%s@%d: st=%d, rqf=%x, rpf=%x, rqh=%d, rqs=%d, rh=%d, rs=%d\n",
Willy Tarreau9a42c0d2009-09-22 19:31:03 +02002435 __FUNCTION__, __LINE__,
Willy Tarreau9b28e032012-10-12 23:49:43 +02002436 si->state, req->flags, res->flags, req->buf->i, req->buf->o, res->buf->i, res->buf->o);
Willy Tarreau5ca791d2009-08-16 19:06:42 +02002437}
2438
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002439/* This function dumps information onto the stream interface's read buffer.
2440 * It returns 0 as long as it does not complete, non-zero upon completion.
2441 * No state is used.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002442 */
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002443static int stats_dump_info_to_buffer(struct stream_interface *si)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002444{
2445 unsigned int up = (now.tv_sec - start_date.tv_sec);
2446
Willy Tarreau0c9c2722014-05-28 12:28:58 +02002447#ifdef USE_OPENSSL
2448 int ssl_sess_rate = read_freq_ctr(&global.ssl_per_sec);
2449 int ssl_key_rate = read_freq_ctr(&global.ssl_fe_keys_per_sec);
2450 int ssl_reuse = 0;
2451
2452 if (ssl_key_rate < ssl_sess_rate) {
2453 /* count the ssl reuse ratio and avoid overflows in both directions */
2454 ssl_reuse = 100 - (100 * ssl_key_rate + (ssl_sess_rate - 1) / 2) / ssl_sess_rate;
2455 }
2456#endif
2457
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002458 chunk_printf(&trash,
2459 "Name: " PRODUCT_NAME "\n"
2460 "Version: " HAPROXY_VERSION "\n"
2461 "Release_date: " HAPROXY_DATE "\n"
2462 "Nbproc: %d\n"
2463 "Process_num: %d\n"
2464 "Pid: %d\n"
2465 "Uptime: %dd %dh%02dm%02ds\n"
2466 "Uptime_sec: %d\n"
2467 "Memmax_MB: %d\n"
2468 "Ulimit-n: %d\n"
2469 "Maxsock: %d\n"
2470 "Maxconn: %d\n"
2471 "Hard_maxconn: %d\n"
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002472 "CurrConns: %d\n"
Willy Tarreau71b734c2014-01-28 15:19:44 +01002473 "CumConns: %d\n"
Warren Turkalb197d7f2015-01-27 15:04:16 -08002474 "CumReq: %u\n"
Willy Tarreau71b734c2014-01-28 15:19:44 +01002475#ifdef USE_OPENSSL
2476 "MaxSslConns: %d\n"
2477 "CurrSslConns: %d\n"
2478 "CumSslConns: %d\n"
2479#endif
2480 "Maxpipes: %d\n"
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002481 "PipesUsed: %d\n"
2482 "PipesFree: %d\n"
2483 "ConnRate: %d\n"
2484 "ConnRateLimit: %d\n"
2485 "MaxConnRate: %d\n"
Willy Tarreau93e7c002013-10-07 18:51:07 +02002486 "SessRate: %d\n"
2487 "SessRateLimit: %d\n"
2488 "MaxSessRate: %d\n"
Willy Tarreaue43d5322013-10-07 20:01:52 +02002489#ifdef USE_OPENSSL
2490 "SslRate: %d\n"
2491 "SslRateLimit: %d\n"
2492 "MaxSslRate: %d\n"
Willy Tarreau0c9c2722014-05-28 12:28:58 +02002493 "SslFrontendKeyRate: %d\n"
2494 "SslFrontendMaxKeyRate: %d\n"
2495 "SslFrontendSessionReuse_pct: %d\n"
2496 "SslBackendKeyRate: %d\n"
2497 "SslBackendMaxKeyRate: %d\n"
Willy Tarreauce3f9132014-05-28 16:47:01 +02002498 "SslCacheLookups: %u\n"
2499 "SslCacheMisses: %u\n"
Willy Tarreaue43d5322013-10-07 20:01:52 +02002500#endif
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002501 "CompressBpsIn: %u\n"
2502 "CompressBpsOut: %u\n"
2503 "CompressBpsRateLim: %u\n"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002504#ifdef USE_ZLIB
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002505 "ZlibMemUsage: %ld\n"
2506 "MaxZlibMemUsage: %ld\n"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002507#endif
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002508 "Tasks: %d\n"
2509 "Run_queue: %d\n"
2510 "Idle_pct: %d\n"
2511 "node: %s\n"
2512 "description: %s\n"
2513 "",
2514 global.nbproc,
2515 relative_pid,
2516 pid,
2517 up / 86400, (up % 86400) / 3600, (up % 3600) / 60, (up % 60),
2518 up,
2519 global.rlimit_memmax,
2520 global.rlimit_nofile,
Willy Tarreau71b734c2014-01-28 15:19:44 +01002521 global.maxsock, global.maxconn, global.hardmaxconn,
2522 actconn, totalconn, global.req_count,
2523#ifdef USE_OPENSSL
2524 global.maxsslconn, sslconns, totalsslconns,
2525#endif
2526 global.maxpipes, pipes_used, pipes_free,
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002527 read_freq_ctr(&global.conn_per_sec), global.cps_lim, global.cps_max,
Willy Tarreau93e7c002013-10-07 18:51:07 +02002528 read_freq_ctr(&global.sess_per_sec), global.sps_lim, global.sps_max,
Willy Tarreaue43d5322013-10-07 20:01:52 +02002529#ifdef USE_OPENSSL
Willy Tarreau0c9c2722014-05-28 12:28:58 +02002530 ssl_sess_rate, global.ssl_lim, global.ssl_max,
2531 ssl_key_rate, global.ssl_fe_keys_max,
2532 ssl_reuse,
2533 read_freq_ctr(&global.ssl_be_keys_per_sec), global.ssl_be_keys_max,
Willy Tarreauce3f9132014-05-28 16:47:01 +02002534 global.shctx_lookups, global.shctx_misses,
Willy Tarreaue43d5322013-10-07 20:01:52 +02002535#endif
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002536 read_freq_ctr(&global.comp_bps_in), read_freq_ctr(&global.comp_bps_out),
2537 global.comp_rate_lim,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002538#ifdef USE_ZLIB
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002539 zlib_used_memory, global.maxzlibmem,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002540#endif
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01002541 nb_tasks_cur, run_queue_cur, idle_pct,
2542 global.node, global.desc ? global.desc : ""
2543 );
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002544
Willy Tarreaubc18da12015-03-13 14:00:47 +01002545 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02002546 si_applet_cant_put(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002547 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002548 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002549
2550 return 1;
2551}
2552
Willy Tarreau12833bb2014-01-28 16:49:56 +01002553/* This function dumps memory usage information onto the stream interface's
2554 * read buffer. It returns 0 as long as it does not complete, non-zero upon
2555 * completion. No state is used.
2556 */
2557static int stats_dump_pools_to_buffer(struct stream_interface *si)
2558{
2559 dump_pools_to_trash();
Willy Tarreaubc18da12015-03-13 14:00:47 +01002560 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02002561 si_applet_cant_put(si);
Willy Tarreau12833bb2014-01-28 16:49:56 +01002562 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002563 }
Willy Tarreau12833bb2014-01-28 16:49:56 +01002564 return 1;
2565}
2566
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002567/* Dumps a frontend's line to the trash for the current proxy <px> and uses
2568 * the state from stream interface <si>. The caller is responsible for clearing
2569 * the trash if needed. Returns non-zero if it emits anything, zero otherwise.
Cyril Bonté70be45d2010-10-12 00:14:35 +02002570 */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002571static int stats_dump_fe_stats(struct stream_interface *si, struct proxy *px)
Cyril Bonté70be45d2010-10-12 00:14:35 +02002572{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002573 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002574 int i;
Cyril Bonté70be45d2010-10-12 00:14:35 +02002575
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002576 if (!(px->cap & PR_CAP_FE))
2577 return 0;
Cyril Bonté70be45d2010-10-12 00:14:35 +02002578
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002579 if ((appctx->ctx.stats.flags & STAT_BOUND) && !(appctx->ctx.stats.type & (1 << STATS_TYPE_FE)))
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002580 return 0;
2581
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002582 if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002583 chunk_appendf(&trash,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002584 /* name, queue */
2585 "<tr class=\"frontend\">");
Cyril Bonté70be45d2010-10-12 00:14:35 +02002586
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002587 if (px->cap & PR_CAP_BE && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN)) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002588 /* Column sub-heading for Enable or Disable server */
2589 chunk_appendf(&trash, "<td></td>");
2590 }
Cyril Bonté70be45d2010-10-12 00:14:35 +02002591
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002592 chunk_appendf(&trash,
2593 "<td class=ac>"
2594 "<a name=\"%s/Frontend\"></a>"
2595 "<a class=lfsb href=\"#%s/Frontend\">Frontend</a></td>"
2596 "<td colspan=3></td>"
2597 "",
2598 px->id, px->id);
Cyril Bonté70be45d2010-10-12 00:14:35 +02002599
Willy Tarreau466c9b52012-12-23 02:25:03 +01002600 chunk_appendf(&trash,
2601 /* sessions rate : current */
Willy Tarreau656a9ce2013-04-19 14:41:29 +02002602 "<td><u>%s<div class=tips><table class=det>"
Willy Tarreau466c9b52012-12-23 02:25:03 +01002603 "<tr><th>Current connection rate:</th><td>%s/s</td></tr>"
2604 "<tr><th>Current session rate:</th><td>%s/s</td></tr>"
2605 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002606 U2H(read_freq_ctr(&px->fe_sess_per_sec)),
2607 U2H(read_freq_ctr(&px->fe_conn_per_sec)),
2608 U2H(read_freq_ctr(&px->fe_sess_per_sec)));
Willy Tarreau466c9b52012-12-23 02:25:03 +01002609
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002610 if (px->mode == PR_MODE_HTTP)
2611 chunk_appendf(&trash,
Willy Tarreau466c9b52012-12-23 02:25:03 +01002612 "<tr><th>Current request rate:</th><td>%s/s</td></tr>",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002613 U2H(read_freq_ctr(&px->fe_req_per_sec)));
Willy Tarreau466c9b52012-12-23 02:25:03 +01002614
2615 chunk_appendf(&trash,
2616 "</table></div></u></td>"
2617 /* sessions rate : max */
Willy Tarreau656a9ce2013-04-19 14:41:29 +02002618 "<td><u>%s<div class=tips><table class=det>"
Willy Tarreau466c9b52012-12-23 02:25:03 +01002619 "<tr><th>Max connection rate:</th><td>%s/s</td></tr>"
2620 "<tr><th>Max session rate:</th><td>%s/s</td></tr>"
2621 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002622 U2H(px->fe_counters.sps_max),
2623 U2H(px->fe_counters.cps_max),
2624 U2H(px->fe_counters.sps_max));
Willy Tarreau466c9b52012-12-23 02:25:03 +01002625
2626 if (px->mode == PR_MODE_HTTP)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002627 chunk_appendf(&trash,
Willy Tarreau466c9b52012-12-23 02:25:03 +01002628 "<tr><th>Max request rate:</th><td>%s/s</td></tr>",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002629 U2H(px->fe_counters.p.http.rps_max));
Willy Tarreau466c9b52012-12-23 02:25:03 +01002630
2631 chunk_appendf(&trash,
2632 "</table></div></u></td>"
2633 /* sessions rate : limit */
2634 "<td>%s</td>",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002635 LIM2A(px->fe_sps_lim, "-"));
Cyril Bonté70be45d2010-10-12 00:14:35 +02002636
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002637 chunk_appendf(&trash,
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01002638 /* sessions: current, max, limit, total */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002639 "<td>%s</td><td>%s</td><td>%s</td>"
Willy Tarreau656a9ce2013-04-19 14:41:29 +02002640 "<td><u>%s<div class=tips><table class=det>"
Willy Tarreau466c9b52012-12-23 02:25:03 +01002641 "<tr><th>Cum. connections:</th><td>%s</td></tr>"
2642 "<tr><th>Cum. sessions:</th><td>%s</td></tr>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002643 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002644 U2H(px->feconn), U2H(px->fe_counters.conn_max), U2H(px->maxconn),
2645 U2H(px->fe_counters.cum_sess),
2646 U2H(px->fe_counters.cum_conn),
2647 U2H(px->fe_counters.cum_sess));
Cyril Bonté70be45d2010-10-12 00:14:35 +02002648
Willy Tarreau466c9b52012-12-23 02:25:03 +01002649 /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002650 if (px->mode == PR_MODE_HTTP) {
Willy Tarreau466c9b52012-12-23 02:25:03 +01002651 chunk_appendf(&trash,
2652 "<tr><th>Cum. HTTP requests:</th><td>%s</td></tr>"
2653 "<tr><th>- HTTP 1xx responses:</th><td>%s</td></tr>"
2654 "<tr><th>- HTTP 2xx responses:</th><td>%s</td></tr>"
2655 "<tr><th>&nbsp;&nbsp;Compressed 2xx:</th><td>%s</td><td>(%d%%)</td></tr>"
2656 "<tr><th>- HTTP 3xx responses:</th><td>%s</td></tr>"
2657 "<tr><th>- HTTP 4xx responses:</th><td>%s</td></tr>"
2658 "<tr><th>- HTTP 5xx responses:</th><td>%s</td></tr>"
2659 "<tr><th>- other responses:</th><td>%s</td></tr>"
2660 "<tr><th>Intercepted requests:</th><td>%s</td></tr>"
2661 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002662 U2H(px->fe_counters.p.http.cum_req),
2663 U2H(px->fe_counters.p.http.rsp[1]),
2664 U2H(px->fe_counters.p.http.rsp[2]),
2665 U2H(px->fe_counters.p.http.comp_rsp),
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002666 px->fe_counters.p.http.rsp[2] ?
Willy Tarreau466c9b52012-12-23 02:25:03 +01002667 (int)(100*px->fe_counters.p.http.comp_rsp/px->fe_counters.p.http.rsp[2]) : 0,
Willy Tarreau56adcf22012-12-23 18:00:29 +01002668 U2H(px->fe_counters.p.http.rsp[3]),
2669 U2H(px->fe_counters.p.http.rsp[4]),
2670 U2H(px->fe_counters.p.http.rsp[5]),
2671 U2H(px->fe_counters.p.http.rsp[0]),
2672 U2H(px->fe_counters.intercepted_req));
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002673 }
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002674
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002675 chunk_appendf(&trash,
Willy Tarreau466c9b52012-12-23 02:25:03 +01002676 "</table></div></u></td>"
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05002677 /* sessions: lbtot, lastsess */
2678 "<td></td><td></td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002679 /* bytes : in */
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01002680 "<td>%s</td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002681 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002682 U2H(px->fe_counters.bytes_in));
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002683
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002684 chunk_appendf(&trash,
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01002685 /* bytes:out + compression stats (via hover): comp_in, comp_out, comp_byp */
Willy Tarreau656a9ce2013-04-19 14:41:29 +02002686 "<td>%s%s<div class=tips>compression: in=%lld out=%lld bypassed=%lld savings=%d%%</div>%s</td>",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002687 (px->fe_counters.comp_in || px->fe_counters.comp_byp) ? "<u>":"",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002688 U2H(px->fe_counters.bytes_out),
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01002689 px->fe_counters.comp_in, px->fe_counters.comp_out, px->fe_counters.comp_byp,
2690 px->fe_counters.comp_in ?
2691 (int)((px->fe_counters.comp_in - px->fe_counters.comp_out)*100/px->fe_counters.comp_in) : 0,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002692 (px->fe_counters.comp_in || px->fe_counters.comp_byp) ? "</u>":"");
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002693
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002694 chunk_appendf(&trash,
2695 /* denied: req, resp */
2696 "<td>%s</td><td>%s</td>"
2697 /* errors : request, connect, response */
2698 "<td>%s</td><td></td><td></td>"
2699 /* warnings: retries, redispatches */
2700 "<td></td><td></td>"
2701 /* server status : reflect frontend status */
2702 "<td class=ac>%s</td>"
2703 /* rest of server: nothing */
2704 "<td class=ac colspan=8></td></tr>"
2705 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002706 U2H(px->fe_counters.denied_req), U2H(px->fe_counters.denied_resp),
2707 U2H(px->fe_counters.failed_req),
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002708 px->state == PR_STREADY ? "OPEN" :
2709 px->state == PR_STFULL ? "FULL" : "STOP");
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002710 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002711 else { /* CSV mode */
2712 chunk_appendf(&trash,
2713 /* pxid, name, queue cur, queue max, */
2714 "%s,FRONTEND,,,"
Willy Tarreauf522f3d2014-02-10 22:22:49 +01002715 /* sessions : current, max, limit, total */
2716 "%d,%d,%d,%lld,"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002717 /* bytes : in, out */
2718 "%lld,%lld,"
2719 /* denied: req, resp */
2720 "%lld,%lld,"
2721 /* errors : request, connect, response */
2722 "%lld,,,"
2723 /* warnings: retries, redispatches */
2724 ",,"
2725 /* server status : reflect frontend status */
2726 "%s,"
2727 /* rest of server: nothing */
2728 ",,,,,,,,"
2729 /* pid, iid, sid, throttle, lbtot, tracked, type */
2730 "%d,%d,0,,,,%d,"
2731 /* rate, rate_lim, rate_max */
2732 "%u,%u,%u,"
2733 /* check_status, check_code, check_duration */
2734 ",,,",
2735 px->id,
2736 px->feconn, px->fe_counters.conn_max, px->maxconn, px->fe_counters.cum_sess,
2737 px->fe_counters.bytes_in, px->fe_counters.bytes_out,
2738 px->fe_counters.denied_req, px->fe_counters.denied_resp,
2739 px->fe_counters.failed_req,
2740 px->state == PR_STREADY ? "OPEN" :
2741 px->state == PR_STFULL ? "FULL" : "STOP",
2742 relative_pid, px->uuid, STATS_TYPE_FE,
2743 read_freq_ctr(&px->fe_sess_per_sec),
2744 px->fe_sps_lim, px->fe_counters.sps_max);
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002745
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002746 /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
2747 if (px->mode == PR_MODE_HTTP) {
2748 for (i=1; i<6; i++)
2749 chunk_appendf(&trash, "%lld,", px->fe_counters.p.http.rsp[i]);
2750 chunk_appendf(&trash, "%lld,", px->fe_counters.p.http.rsp[0]);
2751 }
2752 else
2753 chunk_appendf(&trash, ",,,,,,");
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002754
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002755 /* failed health analyses */
2756 chunk_appendf(&trash, ",");
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002757
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002758 /* requests : req_rate, req_rate_max, req_tot, */
2759 chunk_appendf(&trash, "%u,%u,%lld,",
2760 read_freq_ctr(&px->fe_req_per_sec),
2761 px->fe_counters.p.http.rps_max, px->fe_counters.p.http.cum_req);
2762
2763 /* errors: cli_aborts, srv_aborts */
2764 chunk_appendf(&trash, ",,");
2765
2766 /* compression: in, out, bypassed */
2767 chunk_appendf(&trash, "%lld,%lld,%lld,",
2768 px->fe_counters.comp_in, px->fe_counters.comp_out, px->fe_counters.comp_byp);
2769
2770 /* compression: comp_rsp */
2771 chunk_appendf(&trash, "%lld,",
2772 px->fe_counters.p.http.comp_rsp);
2773
Willy Tarreauf5b1cc32014-06-17 12:20:59 +02002774 /* lastsess, last_chk, last_agt, qtime, ctime, rtime, ttime, */
2775 chunk_appendf(&trash, ",,,,,,,");
Willy Tarreauf522f3d2014-02-10 22:22:49 +01002776
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002777 /* finish with EOL */
2778 chunk_appendf(&trash, "\n");
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002779 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002780 return 1;
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02002781}
2782
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002783/* Dumps a line for listener <l> and proxy <px> to the trash and uses the state
2784 * from stream interface <si>, and stats flags <flags>. The caller is responsible
2785 * for clearing the trash if needed. Returns non-zero if it emits anything, zero
2786 * otherwise.
Willy Tarreau91861262007-10-17 17:06:05 +02002787 */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002788static int stats_dump_li_stats(struct stream_interface *si, struct proxy *px, struct listener *l, int flags)
Willy Tarreau91861262007-10-17 17:06:05 +02002789{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002790 struct appctx *appctx = __objt_appctx(si->end);
2791
2792 if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002793 chunk_appendf(&trash, "<tr class=socket>");
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002794 if (px->cap & PR_CAP_BE && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN)) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002795 /* Column sub-heading for Enable or Disable server */
2796 chunk_appendf(&trash, "<td></td>");
2797 }
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01002798 chunk_appendf(&trash,
2799 /* frontend name, listener name */
2800 "<td class=ac><a name=\"%s/+%s\"></a>%s"
2801 "<a class=lfsb href=\"#%s/+%s\">%s</a>"
2802 "",
2803 px->id, l->name,
2804 (flags & ST_SHLGNDS)?"<u>":"",
2805 px->id, l->name, l->name);
Willy Tarreau91861262007-10-17 17:06:05 +02002806
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002807 if (flags & ST_SHLGNDS) {
2808 char str[INET6_ADDRSTRLEN];
2809 int port;
Willy Tarreau91861262007-10-17 17:06:05 +02002810
Willy Tarreau656a9ce2013-04-19 14:41:29 +02002811 chunk_appendf(&trash, "<div class=tips>");
Willy Tarreau91861262007-10-17 17:06:05 +02002812
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002813 port = get_host_port(&l->addr);
2814 switch (addr_to_str(&l->addr, str, sizeof(str))) {
2815 case AF_INET:
2816 chunk_appendf(&trash, "IPv4: %s:%d, ", str, port);
2817 break;
2818 case AF_INET6:
2819 chunk_appendf(&trash, "IPv6: [%s]:%d, ", str, port);
2820 break;
2821 case AF_UNIX:
2822 chunk_appendf(&trash, "unix, ");
2823 break;
2824 case -1:
2825 chunk_appendf(&trash, "(%s), ", strerror(errno));
2826 break;
2827 }
Willy Tarreau91861262007-10-17 17:06:05 +02002828
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002829 /* id */
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01002830 chunk_appendf(&trash, "id: %d</div>", l->luid);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002831 }
Willy Tarreau91861262007-10-17 17:06:05 +02002832
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002833 chunk_appendf(&trash,
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01002834 /* queue */
2835 "%s</td><td colspan=3></td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002836 /* sessions rate: current, max, limit */
2837 "<td colspan=3>&nbsp;</td>"
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05002838 /* sessions: current, max, limit, total, lbtot, lastsess */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002839 "<td>%s</td><td>%s</td><td>%s</td>"
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05002840 "<td>%s</td><td>&nbsp;</td><td>&nbsp;</td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002841 /* bytes: in, out */
2842 "<td>%s</td><td>%s</td>"
2843 "",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002844 (flags & ST_SHLGNDS)?"</u>":"",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002845 U2H(l->nbconn), U2H(l->counters->conn_max), U2H(l->maxconn),
2846 U2H(l->counters->cum_conn), U2H(l->counters->bytes_in), U2H(l->counters->bytes_out));
Willy Tarreau56a560a2009-09-22 19:27:35 +02002847
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002848 chunk_appendf(&trash,
2849 /* denied: req, resp */
2850 "<td>%s</td><td>%s</td>"
2851 /* errors: request, connect, response */
2852 "<td>%s</td><td></td><td></td>"
2853 /* warnings: retries, redispatches */
2854 "<td></td><td></td>"
2855 /* server status: reflect listener status */
2856 "<td class=ac>%s</td>"
2857 /* rest of server: nothing */
2858 "<td class=ac colspan=8></td></tr>"
2859 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01002860 U2H(l->counters->denied_req), U2H(l->counters->denied_resp),
2861 U2H(l->counters->failed_req),
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002862 (l->nbconn < l->maxconn) ? (l->state == LI_LIMITED) ? "WAITING" : "OPEN" : "FULL");
2863 }
2864 else { /* CSV mode */
2865 chunk_appendf(&trash,
2866 /* pxid, name, queue cur, queue max, */
2867 "%s,%s,,,"
Willy Tarreauf522f3d2014-02-10 22:22:49 +01002868 /* sessions: current, max, limit, total */
2869 "%d,%d,%d,%lld,"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002870 /* bytes: in, out */
2871 "%lld,%lld,"
2872 /* denied: req, resp */
2873 "%lld,%lld,"
2874 /* errors: request, connect, response */
2875 "%lld,,,"
2876 /* warnings: retries, redispatches */
2877 ",,"
2878 /* server status: reflect listener status */
2879 "%s,"
2880 /* rest of server: nothing */
2881 ",,,,,,,,"
2882 /* pid, iid, sid, throttle, lbtot, tracked, type */
2883 "%d,%d,%d,,,,%d,"
2884 /* rate, rate_lim, rate_max */
2885 ",,,"
2886 /* check_status, check_code, check_duration */
2887 ",,,"
2888 /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
2889 ",,,,,,"
2890 /* failed health analyses */
2891 ","
2892 /* requests : req_rate, req_rate_max, req_tot, */
2893 ",,,"
2894 /* errors: cli_aborts, srv_aborts */
2895 ",,"
2896 /* compression: in, out, bypassed, comp_rsp */
2897 ",,,,"
Willy Tarreauf5b1cc32014-06-17 12:20:59 +02002898 /* lastsess, last_chk, last_agt, qtime, ctime, rtime, ttime, */
2899 ",,,,,,,"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002900 "\n",
2901 px->id, l->name,
2902 l->nbconn, l->counters->conn_max,
2903 l->maxconn, l->counters->cum_conn,
2904 l->counters->bytes_in, l->counters->bytes_out,
2905 l->counters->denied_req, l->counters->denied_resp,
2906 l->counters->failed_req,
2907 (l->nbconn < l->maxconn) ? "OPEN" : "FULL",
2908 relative_pid, px->uuid, l->luid, STATS_TYPE_SO);
2909 }
2910 return 1;
2911}
Willy Tarreau91861262007-10-17 17:06:05 +02002912
Simon Horman4d2eab62015-04-23 14:51:26 +09002913enum srv_stats_state {
2914 SRV_STATS_STATE_DOWN = 0,
2915 SRV_STATS_STATE_DOWN_AGENT,
2916 SRV_STATS_STATE_GOING_UP,
2917 SRV_STATS_STATE_UP_GOING_DOWN,
2918 SRV_STATS_STATE_UP,
2919 SRV_STATS_STATE_NOLB_GOING_DOWN,
2920 SRV_STATS_STATE_NOLB,
2921 SRV_STATS_STATE_DRAIN_GOING_DOWN,
2922 SRV_STATS_STATE_DRAIN,
Simon Hormanb167b6b2015-04-23 14:51:29 +09002923 SRV_STATS_STATE_DRAIN_AGENT,
Simon Horman4d2eab62015-04-23 14:51:26 +09002924 SRV_STATS_STATE_NO_CHECK,
2925
2926 SRV_STATS_STATE_COUNT, /* Must be last */
2927};
2928
Simon Horman837bfa72015-04-23 14:51:27 +09002929enum srv_stats_colour {
2930 SRV_STATS_COLOUR_DOWN = 0,
2931 SRV_STATS_COLOUR_GOING_UP,
2932 SRV_STATS_COLOUR_GOING_DOWN,
2933 SRV_STATS_COLOUR_UP,
2934 SRV_STATS_COLOUR_NOLB,
2935 SRV_STATS_COLOUR_DRAINING,
2936 SRV_STATS_COLOUR_NO_CHECK,
2937
2938 SRV_STATS_COLOUR_COUNT, /* Must be last */
2939};
2940
2941static const char *srv_stats_colour_st[SRV_STATS_COLOUR_COUNT] = {
2942 [SRV_STATS_COLOUR_DOWN] = "down",
2943 [SRV_STATS_COLOUR_GOING_UP] = "going_up",
2944 [SRV_STATS_COLOUR_GOING_DOWN] = "going_down",
2945 [SRV_STATS_COLOUR_UP] = "up",
2946 [SRV_STATS_COLOUR_NOLB] = "nolb",
2947 [SRV_STATS_COLOUR_DRAINING] = "draining",
2948 [SRV_STATS_COLOUR_NO_CHECK] = "no_check",
2949};
2950
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002951/* Dumps a line for server <sv> and proxy <px> to the trash and uses the state
2952 * from stream interface <si>, stats flags <flags>, and server state <state>.
2953 * The caller is responsible for clearing the trash if needed. Returns non-zero
Simon Horman4d2eab62015-04-23 14:51:26 +09002954 * if it emits anything, zero otherwise.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002955 */
Simon Horman4d2eab62015-04-23 14:51:26 +09002956static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, int flags, struct server *sv,
Simon Horman837bfa72015-04-23 14:51:27 +09002957 enum srv_stats_state state, enum srv_stats_colour colour)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002958{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002959 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreau32091232014-05-16 13:52:00 +02002960 struct server *via, *ref;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002961 char str[INET6_ADDRSTRLEN];
2962 struct chunk src;
2963 int i;
Willy Tarreau91861262007-10-17 17:06:05 +02002964
Willy Tarreau32091232014-05-16 13:52:00 +02002965 /* we have "via" which is the tracked server as described in the configuration,
2966 * and "ref" which is the checked server and the end of the chain.
2967 */
2968 via = sv->track ? sv->track : sv;
2969 ref = via;
2970 while (ref->track)
2971 ref = ref->track;
2972
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002973 if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
Simon Horman4d2eab62015-04-23 14:51:26 +09002974 static char *srv_hlt_st[SRV_STATS_STATE_COUNT] = {
2975 [SRV_STATS_STATE_DOWN] = "DOWN",
2976 [SRV_STATS_STATE_DOWN_AGENT] = "DOWN (agent)",
2977 [SRV_STATS_STATE_GOING_UP] = "DN %d/%d &uarr;",
2978 [SRV_STATS_STATE_UP_GOING_DOWN] = "UP %d/%d &darr;",
2979 [SRV_STATS_STATE_UP] = "UP",
2980 [SRV_STATS_STATE_NOLB_GOING_DOWN] = "NOLB %d/%d &darr;",
2981 [SRV_STATS_STATE_NOLB] = "NOLB",
2982 [SRV_STATS_STATE_DRAIN_GOING_DOWN] = "DRAIN %d/%d &darr;",
2983 [SRV_STATS_STATE_DRAIN] = "DRAIN",
Simon Hormanb167b6b2015-04-23 14:51:29 +09002984 [SRV_STATS_STATE_DRAIN_AGENT] = "DRAIN (agent)",
Simon Horman4d2eab62015-04-23 14:51:26 +09002985 [SRV_STATS_STATE_NO_CHECK] = "<i>no check</i>",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002986 };
Willy Tarreau91861262007-10-17 17:06:05 +02002987
Willy Tarreaua0066dd2014-05-16 11:25:16 +02002988 if (sv->admin & SRV_ADMF_MAINT)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002989 chunk_appendf(&trash, "<tr class=\"maintain\">");
2990 else
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002991 chunk_appendf(&trash,
Simon Horman837bfa72015-04-23 14:51:27 +09002992 "<tr class=\"%s_%s\">",
2993 (sv->flags & SRV_F_BACKUP) ? "backup" : "active", srv_stats_colour_st[colour]);
Willy Tarreau91861262007-10-17 17:06:05 +02002994
Willy Tarreau7b4b4992013-12-01 09:15:12 +01002995 if ((px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN))
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002996 chunk_appendf(&trash,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01002997 "<td><input type=\"checkbox\" name=\"s\" value=\"%s\"></td>",
2998 sv->id);
Willy Tarreaub1356cf2008-12-07 16:06:43 +01002999
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003000 chunk_appendf(&trash,
3001 "<td class=ac><a name=\"%s/%s\"></a>%s"
3002 "<a class=lfsb href=\"#%s/%s\">%s</a>"
3003 "",
3004 px->id, sv->id,
3005 (flags & ST_SHLGNDS) ? "<u>" : "",
3006 px->id, sv->id, sv->id);
Willy Tarreau91861262007-10-17 17:06:05 +02003007
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003008 if (flags & ST_SHLGNDS) {
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003009 chunk_appendf(&trash, "<div class=tips>");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003010
3011 switch (addr_to_str(&sv->addr, str, sizeof(str))) {
3012 case AF_INET:
3013 chunk_appendf(&trash, "IPv4: %s:%d, ", str, get_host_port(&sv->addr));
3014 break;
3015 case AF_INET6:
3016 chunk_appendf(&trash, "IPv6: [%s]:%d, ", str, get_host_port(&sv->addr));
3017 break;
3018 case AF_UNIX:
3019 chunk_appendf(&trash, "unix, ");
3020 break;
3021 case -1:
3022 chunk_appendf(&trash, "(%s), ", strerror(errno));
3023 break;
3024 default: /* address family not supported */
3025 break;
Willy Tarreau55bb8452007-10-17 18:44:57 +02003026 }
Willy Tarreau91861262007-10-17 17:06:05 +02003027
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003028 /* id */
3029 chunk_appendf(&trash, "id: %d", sv->puid);
Willy Tarreau91861262007-10-17 17:06:05 +02003030
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003031 /* cookie */
3032 if (sv->cookie) {
3033 chunk_appendf(&trash, ", cookie: '");
Willy Tarreau5031e6a2007-10-18 11:05:48 +02003034
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003035 chunk_initlen(&src, sv->cookie, 0, strlen(sv->cookie));
3036 chunk_htmlencode(&trash, &src);
Willy Tarreaub1356cf2008-12-07 16:06:43 +01003037
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003038 chunk_appendf(&trash, "'");
Cyril Bonté70be45d2010-10-12 00:14:35 +02003039 }
3040
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003041 chunk_appendf(&trash, "</div>");
Willy Tarreau55bb8452007-10-17 18:44:57 +02003042 }
Willy Tarreau91861262007-10-17 17:06:05 +02003043
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003044 chunk_appendf(&trash,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003045 /* queue : current, max, limit */
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003046 "%s</td><td>%s</td><td>%s</td><td>%s</td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003047 /* sessions rate : current, max, limit */
3048 "<td>%s</td><td>%s</td><td></td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003049 "",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003050 (flags & ST_SHLGNDS) ? "</u>" : "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003051 U2H(sv->nbpend), U2H(sv->counters.nbpend_max), LIM2A(sv->maxqueue, "-"),
3052 U2H(read_freq_ctr(&sv->sess_per_sec)), U2H(sv->counters.sps_max));
Willy Tarreau91861262007-10-17 17:06:05 +02003053
Willy Tarreau466c9b52012-12-23 02:25:03 +01003054
3055 chunk_appendf(&trash,
3056 /* sessions: current, max, limit, total */
3057 "<td>%s</td><td>%s</td><td>%s</td>"
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003058 "<td><u>%s<div class=tips><table class=det>"
Willy Tarreau466c9b52012-12-23 02:25:03 +01003059 "<tr><th>Cum. sessions:</th><td>%s</td></tr>"
3060 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003061 U2H(sv->cur_sess), U2H(sv->counters.cur_sess_max), LIM2A(sv->maxconn, "-"),
3062 U2H(sv->counters.cum_sess),
3063 U2H(sv->counters.cum_sess));
Willy Tarreau91861262007-10-17 17:06:05 +02003064
Willy Tarreau466c9b52012-12-23 02:25:03 +01003065 /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
3066 if (px->mode == PR_MODE_HTTP) {
3067 unsigned long long tot;
3068 for (tot = i = 0; i < 6; i++)
3069 tot += sv->counters.p.http.rsp[i];
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003070
Willy Tarreau466c9b52012-12-23 02:25:03 +01003071 chunk_appendf(&trash,
3072 "<tr><th>Cum. HTTP responses:</th><td>%s</td></tr>"
3073 "<tr><th>- HTTP 1xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
3074 "<tr><th>- HTTP 2xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
3075 "<tr><th>- HTTP 3xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
3076 "<tr><th>- HTTP 4xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
3077 "<tr><th>- HTTP 5xx responses:</th><td>%s</td><td>(%d%%)</td></tr>"
3078 "<tr><th>- other responses:</th><td>%s</td><td>(%d%%)</td></tr>"
3079 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003080 U2H(tot),
3081 U2H(sv->counters.p.http.rsp[1]), tot ? (int)(100*sv->counters.p.http.rsp[1] / tot) : 0,
3082 U2H(sv->counters.p.http.rsp[2]), tot ? (int)(100*sv->counters.p.http.rsp[2] / tot) : 0,
3083 U2H(sv->counters.p.http.rsp[3]), tot ? (int)(100*sv->counters.p.http.rsp[3] / tot) : 0,
3084 U2H(sv->counters.p.http.rsp[4]), tot ? (int)(100*sv->counters.p.http.rsp[4] / tot) : 0,
3085 U2H(sv->counters.p.http.rsp[5]), tot ? (int)(100*sv->counters.p.http.rsp[5] / tot) : 0,
3086 U2H(sv->counters.p.http.rsp[0]), tot ? (int)(100*sv->counters.p.http.rsp[0] / tot) : 0);
Willy Tarreau91861262007-10-17 17:06:05 +02003087 }
Willy Tarreau91861262007-10-17 17:06:05 +02003088
Willy Tarreauf5b1cc32014-06-17 12:20:59 +02003089 chunk_appendf(&trash, "<tr><th colspan=3>Avg over last 1024 success. conn.</th></tr>");
3090 chunk_appendf(&trash, "<tr><th>- Queue time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES)));
3091 chunk_appendf(&trash, "<tr><th>- Connect time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES)));
3092 if (px->mode == PR_MODE_HTTP)
3093 chunk_appendf(&trash, "<tr><th>- Response time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES)));
3094 chunk_appendf(&trash, "<tr><th>- Total time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES)));
3095
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003096 chunk_appendf(&trash,
Willy Tarreau466c9b52012-12-23 02:25:03 +01003097 "</table></div></u></td>"
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05003098 /* sessions: lbtot, last */
3099 "<td>%s</td><td>%s</td>",
3100 U2H(sv->counters.cum_lbconn),
3101 human_time(srv_lastsession(sv), 1));
Willy Tarreau91861262007-10-17 17:06:05 +02003102
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003103 chunk_appendf(&trash,
3104 /* bytes : in, out */
3105 "<td>%s</td><td>%s</td>"
3106 /* denied: req, resp */
3107 "<td></td><td>%s</td>"
3108 /* errors : request, connect */
3109 "<td></td><td>%s</td>"
3110 /* errors : response */
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003111 "<td><u>%s<div class=tips>Connection resets during transfers: %lld client, %lld server</div></u></td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003112 /* warnings: retries, redispatches */
3113 "<td>%lld</td><td>%lld</td>"
3114 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003115 U2H(sv->counters.bytes_in), U2H(sv->counters.bytes_out),
3116 U2H(sv->counters.failed_secu),
3117 U2H(sv->counters.failed_conns),
3118 U2H(sv->counters.failed_resp),
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003119 sv->counters.cli_aborts,
3120 sv->counters.srv_aborts,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003121 sv->counters.retries, sv->counters.redispatches);
3122
3123 /* status, lest check */
3124 chunk_appendf(&trash, "<td class=ac>");
3125
Willy Tarreau20125212014-05-13 19:44:56 +02003126 if (sv->admin & SRV_ADMF_MAINT) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003127 chunk_appendf(&trash, "%s ", human_time(now.tv_sec - sv->last_change, 1));
3128 chunk_appendf(&trash, "MAINT");
3129 }
Simon Horman0766e442014-11-12 15:55:54 +09003130 else if ((ref->agent.state & CHK_ST_ENABLED) && !(sv->agent.health) && (ref->state == SRV_ST_STOPPED)) {
Willy Tarreaucf2924b2014-05-23 12:15:15 +02003131 chunk_appendf(&trash, "%s ", human_time(now.tv_sec - ref->last_change, 1));
Willy Tarreauac497072014-05-29 01:04:35 +02003132 /* DOWN (agent) */
3133 chunk_appendf(&trash, srv_hlt_st[1], "GCC: your -Werror=format-security is bogus, annoying, and hides real bugs, I don't thank you, really!");
Willy Tarreaucf2924b2014-05-23 12:15:15 +02003134 }
Willy Tarreauff5ae352013-12-11 20:36:34 +01003135 else if (ref->check.state & CHK_ST_ENABLED) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003136 chunk_appendf(&trash, "%s ", human_time(now.tv_sec - ref->last_change, 1));
3137 chunk_appendf(&trash,
3138 srv_hlt_st[state],
Willy Tarreau892337c2014-05-13 23:41:20 +02003139 (ref->state != SRV_ST_STOPPED) ? (ref->check.health - ref->check.rise + 1) : (ref->check.health),
3140 (ref->state != SRV_ST_STOPPED) ? (ref->check.fall) : (ref->check.rise));
Willy Tarreau55bb8452007-10-17 18:44:57 +02003141 }
Willy Tarreau91861262007-10-17 17:06:05 +02003142
Willy Tarreaucf2924b2014-05-23 12:15:15 +02003143 if ((sv->state == SRV_ST_STOPPED) &&
3144 ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) && !(sv->agent.health)) {
3145 chunk_appendf(&trash,
3146 "</td><td class=ac><u> %s%s",
3147 (sv->agent.state & CHK_ST_INPROGRESS) ? "* " : "",
3148 get_check_status_info(sv->agent.status));
3149
3150 if (sv->agent.status >= HCHK_STATUS_L57DATA)
3151 chunk_appendf(&trash, "/%d", sv->agent.code);
3152
3153 if (sv->agent.status >= HCHK_STATUS_CHECKED && sv->agent.duration >= 0)
3154 chunk_appendf(&trash, " in %lums", sv->agent.duration);
3155
3156 chunk_appendf(&trash, "<div class=tips>%s",
3157 get_check_status_description(sv->agent.status));
3158 if (*sv->agent.desc) {
3159 chunk_appendf(&trash, ": ");
3160 chunk_initlen(&src, sv->agent.desc, 0, strlen(sv->agent.desc));
3161 chunk_htmlencode(&trash, &src);
3162 }
3163 chunk_appendf(&trash, "</div></u>");
3164 }
3165 else if ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) {
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003166 chunk_appendf(&trash,
3167 "</td><td class=ac><u> %s%s",
Willy Tarreau2c115e52013-12-11 19:41:16 +01003168 (sv->check.state & CHK_ST_INPROGRESS) ? "* " : "",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003169 get_check_status_info(sv->check.status));
3170
3171 if (sv->check.status >= HCHK_STATUS_L57DATA)
3172 chunk_appendf(&trash, "/%d", sv->check.code);
3173
3174 if (sv->check.status >= HCHK_STATUS_CHECKED && sv->check.duration >= 0)
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003175 chunk_appendf(&trash, " in %lums", sv->check.duration);
3176
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003177 chunk_appendf(&trash, "<div class=tips>%s",
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003178 get_check_status_description(sv->check.status));
3179 if (*sv->check.desc) {
3180 chunk_appendf(&trash, ": ");
3181 chunk_initlen(&src, sv->check.desc, 0, strlen(sv->check.desc));
3182 chunk_htmlencode(&trash, &src);
3183 }
3184 chunk_appendf(&trash, "</div></u>");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003185 }
3186 else
3187 chunk_appendf(&trash, "</td><td>");
3188
3189 chunk_appendf(&trash,
3190 /* weight */
3191 "</td><td class=ac>%d</td>"
3192 /* act, bck */
3193 "<td class=ac>%s</td><td class=ac>%s</td>"
3194 "",
3195 (sv->eweight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
Willy Tarreauc93cd162014-05-13 15:54:22 +02003196 (sv->flags & SRV_F_BACKUP) ? "-" : "Y",
3197 (sv->flags & SRV_F_BACKUP) ? "Y" : "-");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003198
3199 /* check failures: unique, fatal, down time */
Willy Tarreauff5ae352013-12-11 20:36:34 +01003200 if (sv->check.state & CHK_ST_ENABLED) {
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003201 chunk_appendf(&trash, "<td><u>%lld", ref->counters.failed_checks);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003202
3203 if (ref->observe)
3204 chunk_appendf(&trash, "/%lld", ref->counters.failed_hana);
3205
3206 chunk_appendf(&trash,
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003207 "<div class=tips>Failed Health Checks%s</div></u></td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003208 "<td>%lld</td><td>%s</td>"
3209 "",
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003210 ref->observe ? "/Health Analyses" : "",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003211 ref->counters.down_trans, human_time(srv_downtime(sv), 1));
3212 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02003213 else if (!(sv->admin & SRV_ADMF_FMAINT) && sv != ref) {
3214 /* tracking a server */
3215 chunk_appendf(&trash,
3216 "<td class=ac colspan=3><a class=lfsb href=\"#%s/%s\">via %s/%s</a></td>",
Willy Tarreau32091232014-05-16 13:52:00 +02003217 via->proxy->id, via->id, via->proxy->id, via->id);
Willy Tarreauf4659942013-11-28 10:50:06 +01003218 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003219 else
3220 chunk_appendf(&trash, "<td colspan=3></td>");
3221
3222 /* throttle */
Willy Tarreau892337c2014-05-13 23:41:20 +02003223 if (sv->state == SRV_ST_STARTING && !server_is_draining(sv))
Willy Tarreaud32c3992013-11-21 15:30:45 +01003224 chunk_appendf(&trash, "<td class=ac>%d %%</td></tr>\n", server_throttle_rate(sv));
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003225 else
3226 chunk_appendf(&trash, "<td class=ac>-</td></tr>\n");
3227 }
3228 else { /* CSV mode */
Simon Horman4d2eab62015-04-23 14:51:26 +09003229 static char *srv_hlt_st[SRV_STATS_STATE_COUNT] = {
3230 [SRV_STATS_STATE_DOWN] = "DOWN,",
3231 [SRV_STATS_STATE_DOWN_AGENT] = "DOWN (agent),",
3232 [SRV_STATS_STATE_GOING_UP] = "DOWN %d/%d,",
3233 [SRV_STATS_STATE_UP_GOING_DOWN] = "UP %d/%d,",
3234 [SRV_STATS_STATE_UP] = "UP,",
3235 [SRV_STATS_STATE_NOLB_GOING_DOWN] = "NOLB %d/%d,",
3236 [SRV_STATS_STATE_NOLB] = "NOLB,",
3237 [SRV_STATS_STATE_DRAIN_GOING_DOWN] = "DRAIN %d/%d,",
3238 [SRV_STATS_STATE_DRAIN] = "DRAIN,",
Simon Hormanb167b6b2015-04-23 14:51:29 +09003239 [SRV_STATS_STATE_DRAIN_AGENT] = "DRAIN (agent)",
Simon Horman4d2eab62015-04-23 14:51:26 +09003240 [SRV_STATS_STATE_NO_CHECK] = "no check,"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003241 };
3242
3243 chunk_appendf(&trash,
3244 /* pxid, name */
3245 "%s,%s,"
3246 /* queue : current, max */
3247 "%d,%d,"
Willy Tarreauf522f3d2014-02-10 22:22:49 +01003248 /* sessions : current, max, limit, total */
3249 "%d,%d,%s,%lld,"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003250 /* bytes : in, out */
3251 "%lld,%lld,"
3252 /* denied: req, resp */
3253 ",%lld,"
3254 /* errors : request, connect, response */
3255 ",%lld,%lld,"
3256 /* warnings: retries, redispatches */
3257 "%lld,%lld,"
3258 "",
3259 px->id, sv->id,
3260 sv->nbpend, sv->counters.nbpend_max,
Willy Tarreau56adcf22012-12-23 18:00:29 +01003261 sv->cur_sess, sv->counters.cur_sess_max, LIM2A(sv->maxconn, ""), sv->counters.cum_sess,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003262 sv->counters.bytes_in, sv->counters.bytes_out,
3263 sv->counters.failed_secu,
3264 sv->counters.failed_conns, sv->counters.failed_resp,
3265 sv->counters.retries, sv->counters.redispatches);
3266
3267 /* status */
Willy Tarreaua0066dd2014-05-16 11:25:16 +02003268 if (sv->admin & SRV_ADMF_IMAINT)
Willy Tarreau32091232014-05-16 13:52:00 +02003269 chunk_appendf(&trash, "MAINT (via %s/%s),", via->proxy->id, via->id);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02003270 else if (sv->admin & SRV_ADMF_MAINT)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003271 chunk_appendf(&trash, "MAINT,");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003272 else
3273 chunk_appendf(&trash,
3274 srv_hlt_st[state],
Willy Tarreau892337c2014-05-13 23:41:20 +02003275 (ref->state != SRV_ST_STOPPED) ? (ref->check.health - ref->check.rise + 1) : (ref->check.health),
3276 (ref->state != SRV_ST_STOPPED) ? (ref->check.fall) : (ref->check.rise));
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003277
3278 chunk_appendf(&trash,
3279 /* weight, active, backup */
3280 "%d,%d,%d,"
3281 "",
3282 (sv->eweight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
Willy Tarreauc93cd162014-05-13 15:54:22 +02003283 (sv->flags & SRV_F_BACKUP) ? 0 : 1,
3284 (sv->flags & SRV_F_BACKUP) ? 1 : 0);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003285
3286 /* check failures: unique, fatal; last change, total downtime */
Willy Tarreauff5ae352013-12-11 20:36:34 +01003287 if (sv->check.state & CHK_ST_ENABLED)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003288 chunk_appendf(&trash,
3289 "%lld,%lld,%d,%d,",
3290 sv->counters.failed_checks, sv->counters.down_trans,
3291 (int)(now.tv_sec - sv->last_change), srv_downtime(sv));
3292 else
3293 chunk_appendf(&trash, ",,,,");
3294
3295 /* queue limit, pid, iid, sid, */
3296 chunk_appendf(&trash,
3297 "%s,"
3298 "%d,%d,%d,",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003299 LIM2A(sv->maxqueue, ""),
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003300 relative_pid, px->uuid, sv->puid);
3301
3302 /* throttle */
Willy Tarreau892337c2014-05-13 23:41:20 +02003303 if (sv->state == SRV_ST_STARTING && !server_is_draining(sv))
Willy Tarreaud32c3992013-11-21 15:30:45 +01003304 chunk_appendf(&trash, "%d", server_throttle_rate(sv));
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003305
3306 /* sessions: lbtot */
3307 chunk_appendf(&trash, ",%lld,", sv->counters.cum_lbconn);
3308
3309 /* tracked */
3310 if (sv->track)
3311 chunk_appendf(&trash, "%s/%s,",
3312 sv->track->proxy->id, sv->track->id);
3313 else
3314 chunk_appendf(&trash, ",");
3315
3316 /* type */
3317 chunk_appendf(&trash, "%d,", STATS_TYPE_SV);
3318
3319 /* rate */
3320 chunk_appendf(&trash, "%u,,%u,",
3321 read_freq_ctr(&sv->sess_per_sec),
3322 sv->counters.sps_max);
3323
Willy Tarreauff5ae352013-12-11 20:36:34 +01003324 if (sv->check.state & CHK_ST_ENABLED) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003325 /* check_status */
3326 chunk_appendf(&trash, "%s,", get_check_status_info(sv->check.status));
3327
3328 /* check_code */
3329 if (sv->check.status >= HCHK_STATUS_L57DATA)
3330 chunk_appendf(&trash, "%u,", sv->check.code);
3331 else
3332 chunk_appendf(&trash, ",");
3333
3334 /* check_duration */
3335 if (sv->check.status >= HCHK_STATUS_CHECKED)
3336 chunk_appendf(&trash, "%lu,", sv->check.duration);
3337 else
3338 chunk_appendf(&trash, ",");
3339
3340 }
3341 else
3342 chunk_appendf(&trash, ",,,");
3343
3344 /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
3345 if (px->mode == PR_MODE_HTTP) {
3346 for (i=1; i<6; i++)
3347 chunk_appendf(&trash, "%lld,", sv->counters.p.http.rsp[i]);
3348
3349 chunk_appendf(&trash, "%lld,", sv->counters.p.http.rsp[0]);
3350 }
3351 else
3352 chunk_appendf(&trash, ",,,,,,");
3353
3354 /* failed health analyses */
3355 chunk_appendf(&trash, "%lld,", sv->counters.failed_hana);
3356
3357 /* requests : req_rate, req_rate_max, req_tot, */
3358 chunk_appendf(&trash, ",,,");
3359
3360 /* errors: cli_aborts, srv_aborts */
3361 chunk_appendf(&trash, "%lld,%lld,",
3362 sv->counters.cli_aborts, sv->counters.srv_aborts);
3363
3364 /* compression: in, out, bypassed, comp_rsp */
3365 chunk_appendf(&trash, ",,,,");
3366
Willy Tarreauf522f3d2014-02-10 22:22:49 +01003367 /* lastsess */
3368 chunk_appendf(&trash, "%d,", srv_lastsession(sv));
3369
Willy Tarreaua28df3e2014-06-16 16:40:14 +02003370 /* capture of last check and agent statuses */
3371 chunk_appendf(&trash, "%s,", ((sv->check.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) ? cstr(sv->check.desc) : "");
3372 chunk_appendf(&trash, "%s,", ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) == CHK_ST_ENABLED) ? cstr(sv->agent.desc) : "");
3373
Willy Tarreauf5b1cc32014-06-17 12:20:59 +02003374 /* qtime, ctime, rtime, ttime, */
3375 chunk_appendf(&trash, "%u,%u,%u,%u,",
3376 swrate_avg(sv->counters.q_time, TIME_STATS_SAMPLES),
3377 swrate_avg(sv->counters.c_time, TIME_STATS_SAMPLES),
3378 swrate_avg(sv->counters.d_time, TIME_STATS_SAMPLES),
3379 swrate_avg(sv->counters.t_time, TIME_STATS_SAMPLES));
3380
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003381 /* finish with EOL */
3382 chunk_appendf(&trash, "\n");
3383 }
3384 return 1;
3385}
3386
3387/* Dumps a line for backend <px> to the trash for and uses the state from stream
3388 * interface <si> and stats flags <flags>. The caller is responsible for clearing
3389 * the trash if needed. Returns non-zero if it emits anything, zero otherwise.
3390 */
3391static int stats_dump_be_stats(struct stream_interface *si, struct proxy *px, int flags)
3392{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003393 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003394 struct chunk src;
3395 int i;
3396
3397 if (!(px->cap & PR_CAP_BE))
3398 return 0;
3399
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003400 if ((appctx->ctx.stats.flags & STAT_BOUND) && !(appctx->ctx.stats.type & (1 << STATS_TYPE_BE)))
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003401 return 0;
3402
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003403 if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003404 chunk_appendf(&trash, "<tr class=\"backend\">");
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003405 if (px->srv && (appctx->ctx.stats.flags & STAT_ADMIN)) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003406 /* Column sub-heading for Enable or Disable server */
3407 chunk_appendf(&trash, "<td></td>");
3408 }
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003409 chunk_appendf(&trash,
3410 "<td class=ac>"
3411 /* name */
3412 "%s<a name=\"%s/Backend\"></a>"
3413 "<a class=lfsb href=\"#%s/Backend\">Backend</a>"
3414 "",
3415 (flags & ST_SHLGNDS)?"<u>":"",
3416 px->id, px->id);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003417
3418 if (flags & ST_SHLGNDS) {
3419 /* balancing */
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003420 chunk_appendf(&trash, "<div class=tips>balancing: %s",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003421 backend_lb_algo_str(px->lbprm.algo & BE_LB_ALGO));
3422
3423 /* cookie */
3424 if (px->cookie_name) {
3425 chunk_appendf(&trash, ", cookie: '");
3426 chunk_initlen(&src, px->cookie_name, 0, strlen(px->cookie_name));
3427 chunk_htmlencode(&trash, &src);
3428 chunk_appendf(&trash, "'");
3429 }
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003430 chunk_appendf(&trash, "</div>");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003431 }
3432
3433 chunk_appendf(&trash,
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003434 "%s</td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003435 /* queue : current, max */
3436 "<td>%s</td><td>%s</td><td></td>"
3437 /* sessions rate : current, max, limit */
3438 "<td>%s</td><td>%s</td><td></td>"
3439 "",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003440 (flags & ST_SHLGNDS)?"</u>":"",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003441 U2H(px->nbpend) /* or px->totpend ? */, U2H(px->be_counters.nbpend_max),
3442 U2H(read_freq_ctr(&px->be_sess_per_sec)), U2H(px->be_counters.sps_max));
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003443
3444 chunk_appendf(&trash,
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003445 /* sessions: current, max, limit, total */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003446 "<td>%s</td><td>%s</td><td>%s</td>"
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003447 "<td><u>%s<div class=tips><table class=det>"
Willy Tarreau466c9b52012-12-23 02:25:03 +01003448 "<tr><th>Cum. sessions:</th><td>%s</td></tr>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003449 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003450 U2H(px->beconn), U2H(px->be_counters.conn_max), U2H(px->fullconn),
3451 U2H(px->be_counters.cum_conn),
3452 U2H(px->be_counters.cum_conn));
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003453
Willy Tarreau466c9b52012-12-23 02:25:03 +01003454 /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003455 if (px->mode == PR_MODE_HTTP) {
Willy Tarreau466c9b52012-12-23 02:25:03 +01003456 chunk_appendf(&trash,
3457 "<tr><th>Cum. HTTP requests:</th><td>%s</td></tr>"
3458 "<tr><th>- HTTP 1xx responses:</th><td>%s</td></tr>"
3459 "<tr><th>- HTTP 2xx responses:</th><td>%s</td></tr>"
3460 "<tr><th>&nbsp;&nbsp;Compressed 2xx:</th><td>%s</td><td>(%d%%)</td></tr>"
3461 "<tr><th>- HTTP 3xx responses:</th><td>%s</td></tr>"
3462 "<tr><th>- HTTP 4xx responses:</th><td>%s</td></tr>"
3463 "<tr><th>- HTTP 5xx responses:</th><td>%s</td></tr>"
3464 "<tr><th>- other responses:</th><td>%s</td></tr>"
3465 "<tr><th>Intercepted requests:</th><td>%s</td></tr>"
Willy Tarreauf5b1cc32014-06-17 12:20:59 +02003466 "<tr><th colspan=3>Avg over last 1024 success. conn.</th></tr>"
Willy Tarreau466c9b52012-12-23 02:25:03 +01003467 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003468 U2H(px->be_counters.p.http.cum_req),
3469 U2H(px->be_counters.p.http.rsp[1]),
3470 U2H(px->be_counters.p.http.rsp[2]),
3471 U2H(px->be_counters.p.http.comp_rsp),
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003472 px->be_counters.p.http.rsp[2] ?
Willy Tarreau466c9b52012-12-23 02:25:03 +01003473 (int)(100*px->be_counters.p.http.comp_rsp/px->be_counters.p.http.rsp[2]) : 0,
Willy Tarreau56adcf22012-12-23 18:00:29 +01003474 U2H(px->be_counters.p.http.rsp[3]),
3475 U2H(px->be_counters.p.http.rsp[4]),
3476 U2H(px->be_counters.p.http.rsp[5]),
3477 U2H(px->be_counters.p.http.rsp[0]),
3478 U2H(px->be_counters.intercepted_req));
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003479 }
3480
Willy Tarreauf5b1cc32014-06-17 12:20:59 +02003481 chunk_appendf(&trash, "<tr><th>- Queue time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(px->be_counters.q_time, TIME_STATS_SAMPLES)));
3482 chunk_appendf(&trash, "<tr><th>- Connect time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(px->be_counters.c_time, TIME_STATS_SAMPLES)));
3483 if (px->mode == PR_MODE_HTTP)
3484 chunk_appendf(&trash, "<tr><th>- Response time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(px->be_counters.d_time, TIME_STATS_SAMPLES)));
3485 chunk_appendf(&trash, "<tr><th>- Total time:</th><td>%s</td><td>ms</td></tr>", U2H(swrate_avg(px->be_counters.t_time, TIME_STATS_SAMPLES)));
3486
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003487 chunk_appendf(&trash,
Willy Tarreau466c9b52012-12-23 02:25:03 +01003488 "</table></div></u></td>"
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05003489 /* sessions: lbtot, last */
3490 "<td>%s</td><td>%s</td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003491 /* bytes: in */
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003492 "<td>%s</td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003493 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003494 U2H(px->be_counters.cum_lbconn),
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05003495 human_time(be_lastsession(px), 1),
Willy Tarreau56adcf22012-12-23 18:00:29 +01003496 U2H(px->be_counters.bytes_in));
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003497
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003498 chunk_appendf(&trash,
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003499 /* bytes:out + compression stats (via hover): comp_in, comp_out, comp_byp */
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003500 "<td>%s%s<div class=tips>compression: in=%lld out=%lld bypassed=%lld savings=%d%%</div>%s</td>",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003501 (px->be_counters.comp_in || px->be_counters.comp_byp) ? "<u>":"",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003502 U2H(px->be_counters.bytes_out),
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003503 px->be_counters.comp_in, px->be_counters.comp_out, px->be_counters.comp_byp,
3504 px->be_counters.comp_in ?
3505 (int)((px->be_counters.comp_in - px->be_counters.comp_out)*100/px->be_counters.comp_in) : 0,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003506 (px->be_counters.comp_in || px->be_counters.comp_byp) ? "</u>":"");
3507
3508 chunk_appendf(&trash,
3509 /* denied: req, resp */
3510 "<td>%s</td><td>%s</td>"
3511 /* errors : request, connect */
3512 "<td></td><td>%s</td>"
3513 /* errors : response */
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003514 "<td><u>%s<div class=tips>Connection resets during transfers: %lld client, %lld server</div></u></td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003515 /* warnings: retries, redispatches */
3516 "<td>%lld</td><td>%lld</td>"
3517 /* backend status: reflect backend status (up/down): we display UP
3518 * if the backend has known working servers or if it has no server at
3519 * all (eg: for stats). Then we display the total weight, number of
3520 * active and backups. */
3521 "<td class=ac>%s %s</td><td class=ac>&nbsp;</td><td class=ac>%d</td>"
3522 "<td class=ac>%d</td><td class=ac>%d</td>"
3523 "",
Willy Tarreau56adcf22012-12-23 18:00:29 +01003524 U2H(px->be_counters.denied_req), U2H(px->be_counters.denied_resp),
3525 U2H(px->be_counters.failed_conns),
3526 U2H(px->be_counters.failed_resp),
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003527 px->be_counters.cli_aborts,
3528 px->be_counters.srv_aborts,
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003529 px->be_counters.retries, px->be_counters.redispatches,
3530 human_time(now.tv_sec - px->last_change, 1),
3531 (px->lbprm.tot_weight > 0 || !px->srv) ? "UP" :
3532 "<font color=\"red\"><b>DOWN</b></font>",
3533 (px->lbprm.tot_weight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
3534 px->srv_act, px->srv_bck);
3535
3536 chunk_appendf(&trash,
3537 /* rest of backend: nothing, down transitions, total downtime, throttle */
3538 "<td class=ac>&nbsp;</td><td>%d</td>"
3539 "<td>%s</td>"
3540 "<td></td>"
3541 "</tr>",
3542 px->down_trans,
3543 px->srv?human_time(be_downtime(px), 1):"&nbsp;");
3544 }
3545 else { /* CSV mode */
3546 chunk_appendf(&trash,
3547 /* pxid, name */
3548 "%s,BACKEND,"
3549 /* queue : current, max */
3550 "%d,%d,"
Willy Tarreauf522f3d2014-02-10 22:22:49 +01003551 /* sessions : current, max, limit, total */
3552 "%d,%d,%d,%lld,"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003553 /* bytes : in, out */
3554 "%lld,%lld,"
3555 /* denied: req, resp */
3556 "%lld,%lld,"
3557 /* errors : request, connect, response */
3558 ",%lld,%lld,"
3559 /* warnings: retries, redispatches */
3560 "%lld,%lld,"
3561 /* backend status: reflect backend status (up/down): we display UP
3562 * if the backend has known working servers or if it has no server at
3563 * all (eg: for stats). Then we display the total weight, number of
3564 * active and backups. */
3565 "%s,"
3566 "%d,%d,%d,"
3567 /* rest of backend: nothing, down transitions, last change, total downtime */
3568 ",%d,%d,%d,,"
3569 /* pid, iid, sid, throttle, lbtot, tracked, type */
3570 "%d,%d,0,,%lld,,%d,"
3571 /* rate, rate_lim, rate_max, */
3572 "%u,,%u,"
3573 /* check_status, check_code, check_duration */
3574 ",,,",
3575 px->id,
3576 px->nbpend /* or px->totpend ? */, px->be_counters.nbpend_max,
3577 px->beconn, px->be_counters.conn_max, px->fullconn, px->be_counters.cum_conn,
3578 px->be_counters.bytes_in, px->be_counters.bytes_out,
3579 px->be_counters.denied_req, px->be_counters.denied_resp,
3580 px->be_counters.failed_conns, px->be_counters.failed_resp,
3581 px->be_counters.retries, px->be_counters.redispatches,
3582 (px->lbprm.tot_weight > 0 || !px->srv) ? "UP" : "DOWN",
3583 (px->lbprm.tot_weight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
3584 px->srv_act, px->srv_bck,
3585 px->down_trans, (int)(now.tv_sec - px->last_change),
3586 px->srv?be_downtime(px):0,
3587 relative_pid, px->uuid,
3588 px->be_counters.cum_lbconn, STATS_TYPE_BE,
3589 read_freq_ctr(&px->be_sess_per_sec),
3590 px->be_counters.sps_max);
3591
3592 /* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
3593 if (px->mode == PR_MODE_HTTP) {
3594 for (i=1; i<6; i++)
3595 chunk_appendf(&trash, "%lld,", px->be_counters.p.http.rsp[i]);
3596 chunk_appendf(&trash, "%lld,", px->be_counters.p.http.rsp[0]);
3597 }
3598 else
3599 chunk_appendf(&trash, ",,,,,,");
3600
3601 /* failed health analyses */
3602 chunk_appendf(&trash, ",");
3603
3604 /* requests : req_rate, req_rate_max, req_tot, */
3605 chunk_appendf(&trash, ",,,");
3606
3607 /* errors: cli_aborts, srv_aborts */
3608 chunk_appendf(&trash, "%lld,%lld,",
3609 px->be_counters.cli_aborts, px->be_counters.srv_aborts);
3610
3611 /* compression: in, out, bypassed */
3612 chunk_appendf(&trash, "%lld,%lld,%lld,",
3613 px->be_counters.comp_in, px->be_counters.comp_out, px->be_counters.comp_byp);
3614
3615 /* compression: comp_rsp */
3616 chunk_appendf(&trash, "%lld,", px->be_counters.p.http.comp_rsp);
3617
Willy Tarreaua28df3e2014-06-16 16:40:14 +02003618 /* lastsess, last_chk, last_agt, */
3619 chunk_appendf(&trash, "%d,,,", be_lastsession(px));
Willy Tarreauf522f3d2014-02-10 22:22:49 +01003620
Willy Tarreauf5b1cc32014-06-17 12:20:59 +02003621 /* qtime, ctime, rtime, ttime, */
3622 chunk_appendf(&trash, "%u,%u,%u,%u,",
3623 swrate_avg(px->be_counters.q_time, TIME_STATS_SAMPLES),
3624 swrate_avg(px->be_counters.c_time, TIME_STATS_SAMPLES),
3625 swrate_avg(px->be_counters.d_time, TIME_STATS_SAMPLES),
3626 swrate_avg(px->be_counters.t_time, TIME_STATS_SAMPLES));
3627
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003628 /* finish with EOL */
3629 chunk_appendf(&trash, "\n");
3630 }
3631 return 1;
3632}
3633
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003634/* Dumps the HTML table header for proxy <px> to the trash for and uses the state from
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003635 * stream interface <si> and per-uri parameters <uri>. The caller is responsible
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003636 * for clearing the trash if needed.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003637 */
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003638static void stats_dump_html_px_hdr(struct stream_interface *si, struct proxy *px, struct uri_auth *uri)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003639{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003640 struct appctx *appctx = __objt_appctx(si->end);
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003641 char scope_txt[STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN];
3642
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003643 if (px->cap & PR_CAP_BE && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN)) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003644 /* A form to enable/disable this proxy servers */
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003645
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003646 /* scope_txt = search pattern + search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003647 scope_txt[0] = 0;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003648 if (appctx->ctx.stats.scope_len) {
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003649 strcpy(scope_txt, STAT_SCOPE_PATTERN);
Willy Tarreau4e4292b2014-11-28 12:18:45 +01003650 memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), bo_ptr(si_ob(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003651 scope_txt[strlen(STAT_SCOPE_PATTERN) + appctx->ctx.stats.scope_len] = 0;
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003652 }
3653
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003654 chunk_appendf(&trash,
Jeff Buchbinder2dbbf4d2014-08-29 15:10:08 -05003655 "<form method=\"post\">");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003656 }
3657
3658 /* print a new table */
3659 chunk_appendf(&trash,
3660 "<table class=\"tbl\" width=\"100%%\">\n"
3661 "<tr class=\"titre\">"
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003662 "<th class=\"pxname\" width=\"10%%\">");
3663
3664 chunk_appendf(&trash,
3665 "<a name=\"%s\"></a>%s"
3666 "<a class=px href=\"#%s\">%s</a>",
3667 px->id,
3668 (uri->flags & ST_SHLGNDS) ? "<u>":"",
3669 px->id, px->id);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003670
3671 if (uri->flags & ST_SHLGNDS) {
3672 /* cap, mode, id */
Willy Tarreau656a9ce2013-04-19 14:41:29 +02003673 chunk_appendf(&trash, "<div class=tips>cap: %s, mode: %s, id: %d",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003674 proxy_cap_str(px->cap), proxy_mode_str(px->mode),
3675 px->uuid);
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003676 chunk_appendf(&trash, "</div>");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003677 }
3678
3679 chunk_appendf(&trash,
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01003680 "%s</th>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003681 "<th class=\"%s\" width=\"90%%\">%s</th>"
3682 "</tr>\n"
3683 "</table>\n"
3684 "<table class=\"tbl\" width=\"100%%\">\n"
3685 "<tr class=\"titre\">",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003686 (uri->flags & ST_SHLGNDS) ? "</u>":"",
3687 px->desc ? "desc" : "empty", px->desc ? px->desc : "");
3688
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003689 if ((px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN)) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003690 /* Column heading for Enable or Disable server */
3691 chunk_appendf(&trash, "<th rowspan=2 width=1></th>");
Willy Tarreau91861262007-10-17 17:06:05 +02003692 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003693
3694 chunk_appendf(&trash,
3695 "<th rowspan=2></th>"
3696 "<th colspan=3>Queue</th>"
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05003697 "<th colspan=3>Session rate</th><th colspan=6>Sessions</th>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003698 "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
3699 "<th colspan=3>Errors</th><th colspan=2>Warnings</th>"
3700 "<th colspan=9>Server</th>"
3701 "</tr>\n"
3702 "<tr class=\"titre\">"
3703 "<th>Cur</th><th>Max</th><th>Limit</th>"
3704 "<th>Cur</th><th>Max</th><th>Limit</th><th>Cur</th><th>Max</th>"
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05003705 "<th>Limit</th><th>Total</th><th>LbTot</th><th>Last</th><th>In</th><th>Out</th>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003706 "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
3707 "<th>Resp</th><th>Retr</th><th>Redis</th>"
3708 "<th>Status</th><th>LastChk</th><th>Wght</th><th>Act</th>"
3709 "<th>Bck</th><th>Chk</th><th>Dwn</th><th>Dwntme</th>"
3710 "<th>Thrtle</th>\n"
3711 "</tr>");
Willy Tarreau91861262007-10-17 17:06:05 +02003712}
3713
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003714/* Dumps the HTML table trailer for proxy <px> to the trash for and uses the state from
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003715 * stream interface <si>. The caller is responsible for clearing the trash if needed.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003716 */
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003717static void stats_dump_html_px_end(struct stream_interface *si, struct proxy *px)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003718{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003719 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003720 chunk_appendf(&trash, "</table>");
3721
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003722 if ((px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN)) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003723 /* close the form used to enable/disable this proxy servers */
3724 chunk_appendf(&trash,
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003725 "Choose the action to perform on the checked servers : "
3726 "<select name=action>"
3727 "<option value=\"\"></option>"
Willy Tarreaued7df902014-05-22 18:04:49 +02003728 "<option value=\"ready\">Set state to READY</option>"
3729 "<option value=\"drain\">Set state to DRAIN</option>"
Marco Corte8c27bca2014-07-02 17:49:34 +02003730 "<option value=\"maint\">Set state to MAINT</option>"
Willy Tarreau248a60e2014-05-23 14:59:48 +02003731 "<option value=\"dhlth\">Health: disable checks</option>"
3732 "<option value=\"ehlth\">Health: enable checks</option>"
3733 "<option value=\"hrunn\">Health: force UP</option>"
3734 "<option value=\"hnolb\">Health: force NOLB</option>"
3735 "<option value=\"hdown\">Health: force DOWN</option>"
3736 "<option value=\"dagent\">Agent: disable checks</option>"
3737 "<option value=\"eagent\">Agent: enable checks</option>"
3738 "<option value=\"arunn\">Agent: force UP</option>"
3739 "<option value=\"adown\">Agent: force DOWN</option>"
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003740 "<option value=\"shutdown\">Kill Sessions</option>"
3741 "</select>"
3742 "<input type=\"hidden\" name=\"b\" value=\"#%d\">"
3743 "&nbsp;<input type=\"submit\" value=\"Apply\">"
3744 "</form>",
3745 px->uuid);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003746 }
3747
3748 chunk_appendf(&trash, "<p>\n");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003749}
Willy Tarreau91861262007-10-17 17:06:05 +02003750
3751/*
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003752 * Dumps statistics for a proxy. The output is sent to the stream interface's
3753 * input buffer. Returns 0 if it had to stop dumping data because of lack of
3754 * buffer space, or non-zero if everything completed. This function is used
3755 * both by the CLI and the HTTP entry points, and is able to dump the output
3756 * in HTML or CSV formats. If the later, <uri> must be NULL.
Willy Tarreau91861262007-10-17 17:06:05 +02003757 */
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003758static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy *px, struct uri_auth *uri)
Willy Tarreau91861262007-10-17 17:06:05 +02003759{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003760 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreau87b09662015-04-03 00:22:06 +02003761 struct stream *s = si_strm(si);
Willy Tarreau2bb4a962014-11-28 11:11:05 +01003762 struct channel *rep = si_ic(si);
Willy Tarreau44267702011-10-28 15:35:33 +02003763 struct server *sv, *svs; /* server and server-state, server-state=server or server->track */
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003764 struct listener *l;
Willy Tarreau91861262007-10-17 17:06:05 +02003765
Willy Tarreau19d14ef2012-10-29 16:51:55 +01003766 chunk_reset(&trash);
Willy Tarreau91861262007-10-17 17:06:05 +02003767
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003768 switch (appctx->ctx.stats.px_st) {
Willy Tarreau295a8372011-03-10 11:25:07 +01003769 case STAT_PX_ST_INIT:
Willy Tarreau91861262007-10-17 17:06:05 +02003770 /* we are on a new proxy */
Willy Tarreau91861262007-10-17 17:06:05 +02003771 if (uri && uri->scope) {
3772 /* we have a limited scope, we have to check the proxy name */
3773 struct stat_scope *scope;
3774 int len;
3775
3776 len = strlen(px->id);
3777 scope = uri->scope;
3778
3779 while (scope) {
3780 /* match exact proxy name */
3781 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3782 break;
3783
3784 /* match '.' which means 'self' proxy */
Willy Tarreau1388a3a2007-10-18 16:38:37 +02003785 if (!strcmp(scope->px_id, ".") && px == s->be)
Willy Tarreau91861262007-10-17 17:06:05 +02003786 break;
3787 scope = scope->next;
3788 }
3789
3790 /* proxy name not found : don't dump anything */
3791 if (scope == NULL)
3792 return 1;
3793 }
3794
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003795 /* if the user has requested a limited output and the proxy
3796 * name does not match, skip it.
3797 */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003798 if (appctx->ctx.stats.scope_len &&
Willy Tarreau4e4292b2014-11-28 12:18:45 +01003799 strnistr(px->id, strlen(px->id), bo_ptr(si_ob(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len) == NULL)
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003800 return 1;
3801
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003802 if ((appctx->ctx.stats.flags & STAT_BOUND) &&
3803 (appctx->ctx.stats.iid != -1) &&
3804 (px->uuid != appctx->ctx.stats.iid))
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01003805 return 1;
3806
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003807 appctx->ctx.stats.px_st = STAT_PX_ST_TH;
Willy Tarreau91861262007-10-17 17:06:05 +02003808 /* fall through */
3809
Willy Tarreau295a8372011-03-10 11:25:07 +01003810 case STAT_PX_ST_TH:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003811 if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003812 stats_dump_html_px_hdr(si, px, uri);
Willy Tarreaubc18da12015-03-13 14:00:47 +01003813 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02003814 si_applet_cant_put(si);
Willy Tarreau55bb8452007-10-17 18:44:57 +02003815 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01003816 }
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003817 }
Willy Tarreau91861262007-10-17 17:06:05 +02003818
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003819 appctx->ctx.stats.px_st = STAT_PX_ST_FE;
Willy Tarreau91861262007-10-17 17:06:05 +02003820 /* fall through */
3821
Willy Tarreau295a8372011-03-10 11:25:07 +01003822 case STAT_PX_ST_FE:
Willy Tarreau91861262007-10-17 17:06:05 +02003823 /* print the frontend */
Willy Tarreaubc18da12015-03-13 14:00:47 +01003824 if (stats_dump_fe_stats(si, px)) {
3825 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02003826 si_applet_cant_put(si);
Willy Tarreau91861262007-10-17 17:06:05 +02003827 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01003828 }
3829 }
Willy Tarreau91861262007-10-17 17:06:05 +02003830
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003831 appctx->ctx.stats.l = px->conf.listeners.n;
3832 appctx->ctx.stats.px_st = STAT_PX_ST_LI;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003833 /* fall through */
3834
Willy Tarreau295a8372011-03-10 11:25:07 +01003835 case STAT_PX_ST_LI:
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003836 /* stats.l has been initialized above */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003837 for (; appctx->ctx.stats.l != &px->conf.listeners; appctx->ctx.stats.l = l->by_fe.n) {
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01003838 if (buffer_almost_full(rep->buf)) {
Willy Tarreaufe127932015-04-21 19:23:39 +02003839 si_applet_cant_put(si);
Willy Tarreau4e33d862009-10-11 23:35:10 +02003840 return 0;
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01003841 }
Willy Tarreau4e33d862009-10-11 23:35:10 +02003842
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003843 l = LIST_ELEM(appctx->ctx.stats.l, struct listener *, by_fe);
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003844 if (!l->counters)
3845 continue;
3846
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003847 if (appctx->ctx.stats.flags & STAT_BOUND) {
3848 if (!(appctx->ctx.stats.type & (1 << STATS_TYPE_SO)))
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003849 break;
3850
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003851 if (appctx->ctx.stats.sid != -1 && l->luid != appctx->ctx.stats.sid)
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003852 continue;
3853 }
3854
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003855 /* print the frontend */
Willy Tarreaubc18da12015-03-13 14:00:47 +01003856 if (stats_dump_li_stats(si, px, l, uri ? uri->flags : 0)) {
3857 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02003858 si_applet_cant_put(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003859 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01003860 }
3861 }
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003862 }
3863
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003864 appctx->ctx.stats.sv = px->srv; /* may be NULL */
3865 appctx->ctx.stats.px_st = STAT_PX_ST_SV;
Willy Tarreau91861262007-10-17 17:06:05 +02003866 /* fall through */
3867
Willy Tarreau295a8372011-03-10 11:25:07 +01003868 case STAT_PX_ST_SV:
Willy Tarreau91861262007-10-17 17:06:05 +02003869 /* stats.sv has been initialized above */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003870 for (; appctx->ctx.stats.sv != NULL; appctx->ctx.stats.sv = sv->next) {
Simon Horman4d2eab62015-04-23 14:51:26 +09003871 enum srv_stats_state sv_state;
Simon Horman837bfa72015-04-23 14:51:27 +09003872 enum srv_stats_colour sv_colour;
Willy Tarreau91861262007-10-17 17:06:05 +02003873
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01003874 if (buffer_almost_full(rep->buf)) {
Willy Tarreaufe127932015-04-21 19:23:39 +02003875 si_applet_cant_put(si);
Willy Tarreau4e33d862009-10-11 23:35:10 +02003876 return 0;
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01003877 }
Willy Tarreau4e33d862009-10-11 23:35:10 +02003878
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003879 sv = appctx->ctx.stats.sv;
Willy Tarreau91861262007-10-17 17:06:05 +02003880
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003881 if (appctx->ctx.stats.flags & STAT_BOUND) {
3882 if (!(appctx->ctx.stats.type & (1 << STATS_TYPE_SV)))
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01003883 break;
3884
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003885 if (appctx->ctx.stats.sid != -1 && sv->puid != appctx->ctx.stats.sid)
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01003886 continue;
3887 }
3888
Willy Tarreau32091232014-05-16 13:52:00 +02003889 svs = sv;
3890 while (svs->track)
3891 svs = svs->track;
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +01003892
Willy Tarreauf4e38b32014-05-21 15:04:05 +02003893 if (sv->state == SRV_ST_RUNNING || sv->state == SRV_ST_STARTING) {
Willy Tarreauf4e38b32014-05-21 15:04:05 +02003894 if ((svs->check.state & CHK_ST_ENABLED) &&
Simon Horman837bfa72015-04-23 14:51:27 +09003895 (svs->check.health < svs->check.rise + svs->check.fall - 1)) {
Simon Horman4d2eab62015-04-23 14:51:26 +09003896 sv_state = SRV_STATS_STATE_UP_GOING_DOWN;
Simon Horman837bfa72015-04-23 14:51:27 +09003897 sv_colour = SRV_STATS_COLOUR_GOING_DOWN;
3898 } else {
Simon Horman4d2eab62015-04-23 14:51:26 +09003899 sv_state = SRV_STATS_STATE_UP;
Simon Horman837bfa72015-04-23 14:51:27 +09003900 sv_colour = SRV_STATS_COLOUR_UP;
3901 }
Willy Tarreau2ea81932007-11-30 12:04:38 +01003902
Simon Horman4463d192015-04-23 14:51:28 +09003903 if (sv_state == SRV_STATS_STATE_UP && !svs->uweight)
3904 sv_colour = SRV_STATS_COLOUR_DRAINING;
3905
3906 if (sv->admin & SRV_ADMF_DRAIN) {
Simon Hormanb167b6b2015-04-23 14:51:29 +09003907 if (svs->agent.state & CHK_ST_ENABLED)
3908 sv_state = SRV_STATS_STATE_DRAIN_AGENT;
3909 else if (sv_state == SRV_STATS_STATE_UP_GOING_DOWN)
Simon Horman4d2eab62015-04-23 14:51:26 +09003910 sv_state = SRV_STATS_STATE_DRAIN_GOING_DOWN;
Simon Horman4463d192015-04-23 14:51:28 +09003911 else
Simon Horman4d2eab62015-04-23 14:51:26 +09003912 sv_state = SRV_STATS_STATE_DRAIN;
3913 }
Willy Tarreauf4e38b32014-05-21 15:04:05 +02003914
Simon Horman837bfa72015-04-23 14:51:27 +09003915 if (sv_state == SRV_STATS_STATE_UP && !(svs->check.state & CHK_ST_ENABLED)) {
Simon Horman4d2eab62015-04-23 14:51:26 +09003916 sv_state = SRV_STATS_STATE_NO_CHECK;
Simon Horman837bfa72015-04-23 14:51:27 +09003917 sv_colour = SRV_STATS_COLOUR_NO_CHECK;
3918 }
Willy Tarreau2ea81932007-11-30 12:04:38 +01003919 }
Willy Tarreauf4e38b32014-05-21 15:04:05 +02003920 else if (sv->state == SRV_ST_STOPPING) {
3921 if ((!(sv->check.state & CHK_ST_ENABLED) && !sv->track) ||
Simon Horman837bfa72015-04-23 14:51:27 +09003922 (svs->check.health == svs->check.rise + svs->check.fall - 1)) {
Simon Horman4d2eab62015-04-23 14:51:26 +09003923 sv_state = SRV_STATS_STATE_NOLB;
Simon Horman837bfa72015-04-23 14:51:27 +09003924 sv_colour = SRV_STATS_COLOUR_NOLB;
3925 } else {
Simon Horman4d2eab62015-04-23 14:51:26 +09003926 sv_state = SRV_STATS_STATE_NOLB_GOING_DOWN;
Simon Horman837bfa72015-04-23 14:51:27 +09003927 sv_colour = SRV_STATS_COLOUR_GOING_DOWN;
3928 }
Willy Tarreauf4e38b32014-05-21 15:04:05 +02003929 }
3930 else { /* stopped */
Simon Horman837bfa72015-04-23 14:51:27 +09003931 if ((svs->agent.state & CHK_ST_ENABLED) && !svs->agent.health) {
Simon Horman4d2eab62015-04-23 14:51:26 +09003932 sv_state = SRV_STATS_STATE_DOWN_AGENT;
Simon Horman837bfa72015-04-23 14:51:27 +09003933 sv_colour = SRV_STATS_COLOUR_DOWN;
3934 } else if ((svs->check.state & CHK_ST_ENABLED) && !svs->check.health) {
Simon Horman4d2eab62015-04-23 14:51:26 +09003935 sv_state = SRV_STATS_STATE_DOWN; /* DOWN */
Simon Horman837bfa72015-04-23 14:51:27 +09003936 sv_colour = SRV_STATS_COLOUR_DOWN;
3937 } else if ((svs->agent.state & CHK_ST_ENABLED) || (svs->check.state & CHK_ST_ENABLED)) {
Simon Horman4d2eab62015-04-23 14:51:26 +09003938 sv_state = SRV_STATS_STATE_GOING_UP;
Simon Horman837bfa72015-04-23 14:51:27 +09003939 sv_colour = SRV_STATS_COLOUR_GOING_UP;
3940 } else {
Simon Horman4d2eab62015-04-23 14:51:26 +09003941 sv_state = SRV_STATS_STATE_DOWN; /* DOWN, unchecked */
Simon Horman837bfa72015-04-23 14:51:27 +09003942 sv_colour = SRV_STATS_COLOUR_DOWN;
3943 }
Willy Tarreauf4e38b32014-05-21 15:04:05 +02003944 }
Willy Tarreau91861262007-10-17 17:06:05 +02003945
Willy Tarreau9638efa2014-05-23 11:19:57 +02003946 if (((sv_state <= 1) || (sv->admin & SRV_ADMF_MAINT)) && (appctx->ctx.stats.flags & STAT_HIDE_DOWN)) {
Willy Tarreau91861262007-10-17 17:06:05 +02003947 /* do not report servers which are DOWN */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003948 appctx->ctx.stats.sv = sv->next;
Willy Tarreau91861262007-10-17 17:06:05 +02003949 continue;
3950 }
3951
Simon Horman837bfa72015-04-23 14:51:27 +09003952 if (stats_dump_sv_stats(si, px, uri ? uri->flags : 0, sv, sv_state, sv_colour)) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01003953 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02003954 si_applet_cant_put(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003955 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01003956 }
3957 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003958 } /* for sv */
Cyril Bonté474be412010-10-12 00:14:36 +02003959
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003960 appctx->ctx.stats.px_st = STAT_PX_ST_BE;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003961 /* fall through */
Cyril Bonté70be45d2010-10-12 00:14:35 +02003962
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003963 case STAT_PX_ST_BE:
3964 /* print the backend */
Willy Tarreaubc18da12015-03-13 14:00:47 +01003965 if (stats_dump_be_stats(si, px, uri ? uri->flags : 0)) {
3966 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02003967 si_applet_cant_put(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003968 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01003969 }
3970 }
Krzysztof Piotr Oledzki15514c22010-01-04 16:03:09 +01003971
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003972 appctx->ctx.stats.px_st = STAT_PX_ST_END;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003973 /* fall through */
Krzysztof Piotr Oledzki15514c22010-01-04 16:03:09 +01003974
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003975 case STAT_PX_ST_END:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003976 if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003977 stats_dump_html_px_end(si, px);
Willy Tarreaubc18da12015-03-13 14:00:47 +01003978 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02003979 si_applet_cant_put(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003980 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01003981 }
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003982 }
Krzysztof Piotr Oledzki15514c22010-01-04 16:03:09 +01003983
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003984 appctx->ctx.stats.px_st = STAT_PX_ST_FIN;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003985 /* fall through */
Krzysztof Piotr Oledzki15514c22010-01-04 16:03:09 +01003986
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003987 case STAT_PX_ST_FIN:
3988 return 1;
Krzysztof Piotr Oledzki15514c22010-01-04 16:03:09 +01003989
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003990 default:
3991 /* unknown state, we should put an abort() here ! */
3992 return 1;
3993 }
3994}
Krzysztof Piotr Oledzki15514c22010-01-04 16:03:09 +01003995
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003996/* Dumps the HTTP stats head block to the trash for and uses the per-uri
3997 * parameters <uri>. The caller is responsible for clearing the trash if needed.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01003998 */
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01003999static void stats_dump_html_head(struct uri_auth *uri)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004000{
4001 /* WARNING! This must fit in the first buffer !!! */
4002 chunk_appendf(&trash,
4003 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n"
4004 "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
4005 "<html><head><title>Statistics Report for " PRODUCT_NAME "%s%s</title>\n"
4006 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
4007 "<style type=\"text/css\"><!--\n"
4008 "body {"
4009 " font-family: arial, helvetica, sans-serif;"
4010 " font-size: 12px;"
4011 " font-weight: normal;"
4012 " color: black;"
4013 " background: white;"
4014 "}\n"
4015 "th,td {"
4016 " font-size: 10px;"
4017 "}\n"
4018 "h1 {"
4019 " font-size: x-large;"
4020 " margin-bottom: 0.5em;"
4021 "}\n"
4022 "h2 {"
4023 " font-family: helvetica, arial;"
4024 " font-size: x-large;"
4025 " font-weight: bold;"
4026 " font-style: italic;"
4027 " color: #6020a0;"
4028 " margin-top: 0em;"
4029 " margin-bottom: 0em;"
4030 "}\n"
4031 "h3 {"
4032 " font-family: helvetica, arial;"
4033 " font-size: 16px;"
4034 " font-weight: bold;"
4035 " color: #b00040;"
4036 " background: #e8e8d0;"
4037 " margin-top: 0em;"
4038 " margin-bottom: 0em;"
4039 "}\n"
4040 "li {"
4041 " margin-top: 0.25em;"
4042 " margin-right: 2em;"
4043 "}\n"
4044 ".hr {margin-top: 0.25em;"
4045 " border-color: black;"
4046 " border-bottom-style: solid;"
4047 "}\n"
4048 ".titre {background: #20D0D0;color: #000000; font-weight: bold; text-align: center;}\n"
4049 ".total {background: #20D0D0;color: #ffff80;}\n"
4050 ".frontend {background: #e8e8d0;}\n"
4051 ".socket {background: #d0d0d0;}\n"
4052 ".backend {background: #e8e8d0;}\n"
Simon Horman837bfa72015-04-23 14:51:27 +09004053 ".active_down {background: #ff9090;}\n"
4054 ".active_going_up {background: #ffd020;}\n"
4055 ".active_going_down {background: #ffffa0;}\n"
4056 ".active_up {background: #c0ffc0;}\n"
4057 ".active_nolb {background: #20a0ff;}\n"
4058 ".active_draining {background: #20a0FF;}\n"
4059 ".active_no_check {background: #e0e0e0;}\n"
4060 ".backup_down {background: #ff9090;}\n"
4061 ".backup_going_up {background: #ff80ff;}\n"
4062 ".backup_going_down {background: #c060ff;}\n"
4063 ".backup_up {background: #b0d0ff;}\n"
4064 ".backup_nolb {background: #90b0e0;}\n"
4065 ".backup_draining {background: #cc9900;}\n"
4066 ".backup_no_check {background: #e0e0e0;}\n"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004067 ".maintain {background: #c07820;}\n"
4068 ".rls {letter-spacing: 0.2em; margin-right: 1px;}\n" /* right letter spacing (used for grouping digits) */
4069 "\n"
4070 "a.px:link {color: #ffff40; text-decoration: none;}"
4071 "a.px:visited {color: #ffff40; text-decoration: none;}"
4072 "a.px:hover {color: #ffffff; text-decoration: none;}"
4073 "a.lfsb:link {color: #000000; text-decoration: none;}"
4074 "a.lfsb:visited {color: #000000; text-decoration: none;}"
4075 "a.lfsb:hover {color: #505050; text-decoration: none;}"
4076 "\n"
4077 "table.tbl { border-collapse: collapse; border-style: none;}\n"
4078 "table.tbl td { text-align: right; border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray; white-space: nowrap;}\n"
4079 "table.tbl td.ac { text-align: center;}\n"
4080 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
4081 "table.tbl th.pxname { background: #b00040; color: #ffff40; font-weight: bold; border-style: solid solid none solid; padding: 2px 3px; white-space: nowrap;}\n"
4082 "table.tbl th.empty { border-style: none; empty-cells: hide; background: white;}\n"
4083 "table.tbl th.desc { background: white; border-style: solid solid none solid; text-align: left; padding: 2px 3px;}\n"
4084 "\n"
4085 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
4086 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
4087 "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
Willy Tarreau466c9b52012-12-23 02:25:03 +01004088 "table.det { border-collapse: collapse; border-style: none; }\n"
4089 "table.det th { text-align: left; border-width: 0px; padding: 0px 1px 0px 0px; font-style:normal;font-size:11px;font-weight:bold;font-family: sans-serif;}\n"
Willy Tarreau6b9d3a82013-12-16 09:00:35 +01004090 "table.det td { text-align: right; border-width: 0px; padding: 0px 0px 0px 4px; white-space: nowrap; font-style:normal;font-size:11px;font-weight:normal;}\n"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004091 "u {text-decoration:none; border-bottom: 1px dotted black;}\n"
Willy Tarreau656a9ce2013-04-19 14:41:29 +02004092 "div.tips {\n"
Willy Tarreaue7dbfc62012-12-23 01:59:23 +01004093 " display:block;\n"
4094 " visibility:hidden;\n"
4095 " z-index:2147483647;\n"
4096 " position:absolute;\n"
4097 " padding:2px 4px 3px;\n"
4098 " background:#f0f060; color:#000000;\n"
4099 " border:1px solid #7040c0;\n"
4100 " white-space:nowrap;\n"
4101 " font-style:normal;font-size:11px;font-weight:normal;\n"
4102 " -moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;\n"
4103 " -moz-box-shadow:gray 2px 2px 3px;-webkit-box-shadow:gray 2px 2px 3px;box-shadow:gray 2px 2px 3px;\n"
4104 "}\n"
Willy Tarreau656a9ce2013-04-19 14:41:29 +02004105 "u:hover div.tips {visibility:visible;}\n"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004106 "-->\n"
4107 "</style></head>\n",
4108 (uri->flags & ST_SHNODE) ? " on " : "",
4109 (uri->flags & ST_SHNODE) ? (uri->node ? uri->node : global.node) : ""
4110 );
4111}
Krzysztof Piotr Oledzki15514c22010-01-04 16:03:09 +01004112
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004113/* Dumps the HTML stats information block to the trash for and uses the state from
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004114 * stream interface <si> and per-uri parameters <uri>. The caller is responsible
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004115 * for clearing the trash if needed.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004116 */
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004117static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *uri)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004118{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004119 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004120 unsigned int up = (now.tv_sec - start_date.tv_sec);
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004121 char scope_txt[STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN];
Krzysztof Piotr Oledzki15514c22010-01-04 16:03:09 +01004122
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004123 /* WARNING! this has to fit the first packet too.
4124 * We are around 3.5 kB, add adding entries will
4125 * become tricky if we want to support 4kB buffers !
4126 */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004127 chunk_appendf(&trash,
4128 "<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
4129 PRODUCT_NAME "%s</a></h1>\n"
4130 "<h2>Statistics Report for pid %d%s%s%s%s</h2>\n"
4131 "<hr width=\"100%%\" class=\"hr\">\n"
4132 "<h3>&gt; General process information</h3>\n"
4133 "<table border=0><tr><td align=\"left\" nowrap width=\"1%%\">\n"
4134 "<p><b>pid = </b> %d (process #%d, nbproc = %d)<br>\n"
4135 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
4136 "<b>system limits:</b> memmax = %s%s; ulimit-n = %d<br>\n"
4137 "<b>maxsock = </b> %d; <b>maxconn = </b> %d; <b>maxpipes = </b> %d<br>\n"
4138 "current conns = %d; current pipes = %d/%d; conn rate = %d/sec<br>\n"
4139 "Running tasks: %d/%d; idle = %d %%<br>\n"
4140 "</td><td align=\"center\" nowrap>\n"
4141 "<table class=\"lgd\"><tr>\n"
Simon Horman837bfa72015-04-23 14:51:27 +09004142 "<td class=\"active_up\">&nbsp;</td><td class=\"noborder\">active UP </td>"
4143 "<td class=\"backup_up\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004144 "</tr><tr>\n"
Simon Horman837bfa72015-04-23 14:51:27 +09004145 "<td class=\"active_going_down\"></td><td class=\"noborder\">active UP, going down </td>"
4146 "<td class=\"backup_going_down\"></td><td class=\"noborder\">backup UP, going down </td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004147 "</tr><tr>\n"
Simon Horman837bfa72015-04-23 14:51:27 +09004148 "<td class=\"active_going_up\"></td><td class=\"noborder\">active DOWN, going up </td>"
4149 "<td class=\"backup_going_up\"></td><td class=\"noborder\">backup DOWN, going up </td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004150 "</tr><tr>\n"
Simon Horman837bfa72015-04-23 14:51:27 +09004151 "<td class=\"active_down\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
4152 "<td class=\"active_no_check\"></td><td class=\"noborder\">not checked </td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004153 "</tr><tr>\n"
4154 "<td class=\"maintain\"></td><td class=\"noborder\" colspan=\"3\">active or backup DOWN for maintenance (MAINT) &nbsp;</td>"
Geoff Bucarcc8bb922013-04-18 13:53:16 -07004155 "</tr><tr>\n"
Simon Horman837bfa72015-04-23 14:51:27 +09004156 "<td class=\"active_draining\"></td><td class=\"noborder\" colspan=\"3\">active or backup SOFT STOPPED for maintenance &nbsp;</td>"
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004157 "</tr></table>\n"
Willy Tarreau6b7764a2013-12-04 00:43:21 +01004158 "Note: \"NOLB\"/\"DRAIN\" = UP with load-balancing disabled."
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004159 "</td>"
4160 "<td align=\"left\" valign=\"top\" nowrap width=\"1%%\">"
4161 "<b>Display option:</b><ul style=\"margin-top: 0.25em;\">"
4162 "",
4163 (uri->flags & ST_HIDEVER) ? "" : (STATS_VERSION_STRING),
4164 pid, (uri->flags & ST_SHNODE) ? " on " : "",
4165 (uri->flags & ST_SHNODE) ? (uri->node ? uri->node : global.node) : "",
4166 (uri->flags & ST_SHDESC) ? ": " : "",
4167 (uri->flags & ST_SHDESC) ? (uri->desc ? uri->desc : global.desc) : "",
4168 pid, relative_pid, global.nbproc,
4169 up / 86400, (up % 86400) / 3600,
4170 (up % 3600) / 60, (up % 60),
4171 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
4172 global.rlimit_memmax ? " MB" : "",
4173 global.rlimit_nofile,
4174 global.maxsock, global.maxconn, global.maxpipes,
4175 actconn, pipes_used, pipes_used+pipes_free, read_freq_ctr(&global.conn_per_sec),
4176 run_queue_cur, nb_tasks_cur, idle_pct
4177 );
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004178
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004179 /* scope_txt = search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004180 memcpy(scope_txt, bo_ptr(si_ob(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004181 scope_txt[appctx->ctx.stats.scope_len] = '\0';
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004182
4183 chunk_appendf(&trash,
Jeff Buchbinder2dbbf4d2014-08-29 15:10:08 -05004184 "<li><form method=\"GET\">Scope : <input value=\"%s\" name=\"" STAT_SCOPE_INPUT_NAME "\" size=\"8\" maxlength=\"%d\" tabindex=\"1\"/></form>\n",
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004185 (appctx->ctx.stats.scope_len > 0) ? scope_txt : "",
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004186 STAT_SCOPE_TXT_MAXLEN);
4187
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004188 /* scope_txt = search pattern + search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004189 scope_txt[0] = 0;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004190 if (appctx->ctx.stats.scope_len) {
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004191 strcpy(scope_txt, STAT_SCOPE_PATTERN);
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004192 memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), bo_ptr(si_ob(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004193 scope_txt[strlen(STAT_SCOPE_PATTERN) + appctx->ctx.stats.scope_len] = 0;
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004194 }
4195
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004196 if (appctx->ctx.stats.flags & STAT_HIDE_DOWN)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004197 chunk_appendf(&trash,
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004198 "<li><a href=\"%s%s%s%s\">Show all servers</a><br>\n",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004199 uri->uri_prefix,
4200 "",
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004201 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004202 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004203 else
4204 chunk_appendf(&trash,
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004205 "<li><a href=\"%s%s%s%s\">Hide 'DOWN' servers</a><br>\n",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004206 uri->uri_prefix,
4207 ";up",
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004208 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004209 scope_txt);
Willy Tarreau91861262007-10-17 17:06:05 +02004210
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004211 if (uri->refresh > 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004212 if (appctx->ctx.stats.flags & STAT_NO_REFRESH)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004213 chunk_appendf(&trash,
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004214 "<li><a href=\"%s%s%s%s\">Enable refresh</a><br>\n",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004215 uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004216 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004217 "",
4218 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004219 else
4220 chunk_appendf(&trash,
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004221 "<li><a href=\"%s%s%s%s\">Disable refresh</a><br>\n",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004222 uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004223 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004224 ";norefresh",
4225 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004226 }
Willy Tarreau55bb8452007-10-17 18:44:57 +02004227
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004228 chunk_appendf(&trash,
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004229 "<li><a href=\"%s%s%s%s\">Refresh now</a><br>\n",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004230 uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004231 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4232 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004233 scope_txt);
Elijah Epifanovacafc5f2007-10-25 20:15:38 +02004234
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004235 chunk_appendf(&trash,
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004236 "<li><a href=\"%s;csv%s%s\">CSV export</a><br>\n",
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004237 uri->uri_prefix,
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02004238 (uri->refresh > 0) ? ";norefresh" : "",
4239 scope_txt);
Willy Tarreau4bab24d2007-11-30 18:16:29 +01004240
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004241 chunk_appendf(&trash,
4242 "</ul></td>"
4243 "<td align=\"left\" valign=\"top\" nowrap width=\"1%%\">"
4244 "<b>External resources:</b><ul style=\"margin-top: 0.25em;\">\n"
4245 "<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>\n"
4246 "<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>\n"
4247 "<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>\n"
4248 "</ul>"
4249 "</td>"
4250 "</tr></table>\n"
4251 ""
4252 );
Willy Tarreau4bab24d2007-11-30 18:16:29 +01004253
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004254 if (appctx->ctx.stats.st_code) {
4255 switch (appctx->ctx.stats.st_code) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004256 case STAT_STATUS_DONE:
4257 chunk_appendf(&trash,
Simon Horman837bfa72015-04-23 14:51:27 +09004258 "<p><div class=active_up>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004259 "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004260 "Action processed successfully."
Willy Tarreauba6be982013-04-19 12:16:55 +02004261 "</div>\n", uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004262 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4263 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
Willy Tarreauba6be982013-04-19 12:16:55 +02004264 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004265 break;
4266 case STAT_STATUS_NONE:
4267 chunk_appendf(&trash,
Simon Horman837bfa72015-04-23 14:51:27 +09004268 "<p><div class=active_going_down>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004269 "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004270 "Nothing has changed."
Willy Tarreauba6be982013-04-19 12:16:55 +02004271 "</div>\n", uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004272 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4273 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
Willy Tarreauba6be982013-04-19 12:16:55 +02004274 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004275 break;
4276 case STAT_STATUS_PART:
4277 chunk_appendf(&trash,
Simon Horman837bfa72015-04-23 14:51:27 +09004278 "<p><div class=active_going_down>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004279 "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004280 "Action partially processed.<br>"
4281 "Some server names are probably unknown or ambiguous (duplicated names in the backend)."
Willy Tarreauba6be982013-04-19 12:16:55 +02004282 "</div>\n", uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004283 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4284 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
Willy Tarreauba6be982013-04-19 12:16:55 +02004285 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004286 break;
4287 case STAT_STATUS_ERRP:
4288 chunk_appendf(&trash,
Simon Horman837bfa72015-04-23 14:51:27 +09004289 "<p><div class=active_down>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004290 "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004291 "Action not processed because of invalid parameters."
4292 "<ul>"
4293 "<li>The action is maybe unknown.</li>"
4294 "<li>The backend name is probably unknown or ambiguous (duplicated names).</li>"
4295 "<li>Some server names are probably unknown or ambiguous (duplicated names in the backend).</li>"
4296 "</ul>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004297 "</div>\n", uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004298 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4299 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
Willy Tarreauba6be982013-04-19 12:16:55 +02004300 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004301 break;
4302 case STAT_STATUS_EXCD:
4303 chunk_appendf(&trash,
Simon Horman837bfa72015-04-23 14:51:27 +09004304 "<p><div class=active_down>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004305 "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004306 "<b>Action not processed : the buffer couldn't store all the data.<br>"
4307 "You should retry with less servers at a time.</b>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004308 "</div>\n", uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004309 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4310 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
Willy Tarreauba6be982013-04-19 12:16:55 +02004311 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004312 break;
4313 case STAT_STATUS_DENY:
4314 chunk_appendf(&trash,
Simon Horman837bfa72015-04-23 14:51:27 +09004315 "<p><div class=active_down>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004316 "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004317 "<b>Action denied.</b>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004318 "</div>\n", uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004319 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4320 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
Willy Tarreauba6be982013-04-19 12:16:55 +02004321 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004322 break;
4323 default:
4324 chunk_appendf(&trash,
Simon Horman837bfa72015-04-23 14:51:27 +09004325 "<p><div class=active_no_check>"
Willy Tarreauba6be982013-04-19 12:16:55 +02004326 "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004327 "Unexpected result."
Willy Tarreauba6be982013-04-19 12:16:55 +02004328 "</div>\n", uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004329 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4330 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
Willy Tarreauba6be982013-04-19 12:16:55 +02004331 scope_txt);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004332 }
4333 chunk_appendf(&trash, "<p>\n");
4334 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004335}
Krzysztof Piotr Oledzkic8b16fc2008-02-18 01:26:35 +01004336
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004337/* Dumps the HTML stats trailer block to the trash. The caller is responsible
4338 * for clearing the trash if needed.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004339 */
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004340static void stats_dump_html_end()
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004341{
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004342 chunk_appendf(&trash, "</body></html>\n");
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004343}
Willy Tarreau7f062c42009-03-05 18:43:00 +01004344
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004345/* This function dumps statistics onto the stream interface's read buffer in
4346 * either CSV or HTML format. <uri> contains some HTML-specific parameters that
Willy Tarreau306f8302013-07-08 15:53:06 +02004347 * are ignored for CSV format (hence <uri> may be NULL there). It returns 0 if
4348 * it had to stop writing data and an I/O is needed, 1 if the dump is finished
Willy Tarreau87b09662015-04-03 00:22:06 +02004349 * and the stream must be closed, or -1 in case of any error. This function is
Willy Tarreau306f8302013-07-08 15:53:06 +02004350 * used by both the CLI and the HTTP handlers.
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004351 */
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004352static int stats_dump_stat_to_buffer(struct stream_interface *si, struct uri_auth *uri)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004353{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004354 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreau2bb4a962014-11-28 11:11:05 +01004355 struct channel *rep = si_ic(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004356 struct proxy *px;
Willy Tarreau7f062c42009-03-05 18:43:00 +01004357
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004358 chunk_reset(&trash);
Krzysztof Piotr Oledzki09605412009-09-23 22:09:24 +02004359
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004360 switch (appctx->st2) {
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004361 case STAT_ST_INIT:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004362 appctx->st2 = STAT_ST_HEAD; /* let's start producing data */
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004363 /* fall through */
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004364
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004365 case STAT_ST_HEAD:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004366 if (appctx->ctx.stats.flags & STAT_FMT_HTML)
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004367 stats_dump_html_head(uri);
Willy Tarreau354898b2012-12-23 18:15:23 +01004368 else
4369 stats_dump_csv_header();
Willy Tarreaud9b587f2010-02-26 10:05:55 +01004370
Willy Tarreaubc18da12015-03-13 14:00:47 +01004371 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02004372 si_applet_cant_put(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004373 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01004374 }
Willy Tarreauae526782010-03-04 20:34:23 +01004375
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004376 appctx->st2 = STAT_ST_INFO;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004377 /* fall through */
Willy Tarreau5e16cbc2012-11-24 14:54:13 +01004378
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004379 case STAT_ST_INFO:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004380 if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004381 stats_dump_html_info(si, uri);
Willy Tarreaubc18da12015-03-13 14:00:47 +01004382 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02004383 si_applet_cant_put(si);
Willy Tarreau91861262007-10-17 17:06:05 +02004384 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01004385 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004386 }
Willy Tarreau91861262007-10-17 17:06:05 +02004387
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004388 appctx->ctx.stats.px = proxy;
4389 appctx->ctx.stats.px_st = STAT_PX_ST_INIT;
4390 appctx->st2 = STAT_ST_LIST;
Willy Tarreau91861262007-10-17 17:06:05 +02004391 /* fall through */
4392
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004393 case STAT_ST_LIST:
4394 /* dump proxies */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004395 while (appctx->ctx.stats.px) {
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01004396 if (buffer_almost_full(rep->buf)) {
Willy Tarreaufe127932015-04-21 19:23:39 +02004397 si_applet_cant_put(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004398 return 0;
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01004399 }
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004400
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004401 px = appctx->ctx.stats.px;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004402 /* skip the disabled proxies, global frontend and non-networked ones */
4403 if (px->state != PR_STSTOPPED && px->uuid > 0 && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004404 if (stats_dump_proxy_to_buffer(si, px, uri) == 0)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004405 return 0;
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004406
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004407 appctx->ctx.stats.px = px->next;
4408 appctx->ctx.stats.px_st = STAT_PX_ST_INIT;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004409 }
4410 /* here, we just have reached the last proxy */
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004411
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004412 appctx->st2 = STAT_ST_END;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004413 /* fall through */
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004414
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004415 case STAT_ST_END:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004416 if (appctx->ctx.stats.flags & STAT_FMT_HTML) {
Willy Tarreaub5ba4ec2012-12-22 23:20:30 +01004417 stats_dump_html_end();
Willy Tarreaubc18da12015-03-13 14:00:47 +01004418 if (bi_putchk(rep, &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02004419 si_applet_cant_put(si);
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004420 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01004421 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004422 }
Willy Tarreau55058a72012-11-21 08:27:21 +01004423
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004424 appctx->st2 = STAT_ST_FIN;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004425 /* fall through */
Willy Tarreau0a6d2ef2009-03-29 14:46:01 +02004426
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004427 case STAT_ST_FIN:
4428 return 1;
Willy Tarreau55058a72012-11-21 08:27:21 +01004429
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004430 default:
4431 /* unknown state ! */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004432 appctx->st2 = STAT_ST_FIN;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004433 return -1;
4434 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004435}
Willy Tarreauae526782010-03-04 20:34:23 +01004436
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004437/* We reached the stats page through a POST request. The appctx is
4438 * expected to have already been allocated by the caller.
Willy Tarreau347a35d2013-11-22 17:51:09 +01004439 * Parse the posted data and enable/disable servers if necessary.
4440 * Returns 1 if request was parsed or zero if it needs more data.
4441 */
4442static int stats_process_http_post(struct stream_interface *si)
4443{
Willy Tarreau87b09662015-04-03 00:22:06 +02004444 struct stream *s = si_strm(si);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004445 struct appctx *appctx = objt_appctx(si->end);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004446
4447 struct proxy *px = NULL;
4448 struct server *sv = NULL;
4449
4450 char key[LINESIZE];
4451 int action = ST_ADM_ACTION_NONE;
4452 int reprocess = 0;
4453
4454 int total_servers = 0;
4455 int altered_servers = 0;
4456
4457 char *first_param, *cur_param, *next_param, *end_params;
4458 char *st_cur_param = NULL;
4459 char *st_next_param = NULL;
4460
4461 struct chunk *temp;
4462 int reql;
4463
4464 temp = get_trash_chunk();
Willy Tarreaueee5b512015-04-03 23:46:31 +02004465 if (temp->size < s->txn->req.body_len) {
Willy Tarreau347a35d2013-11-22 17:51:09 +01004466 /* too large request */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004467 appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004468 goto out;
4469 }
4470
Willy Tarreaueee5b512015-04-03 23:46:31 +02004471 reql = bo_getblk(si_oc(si), temp->str, s->txn->req.body_len, s->txn->req.eoh + 2);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004472 if (reql <= 0) {
4473 /* we need more data */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004474 appctx->ctx.stats.st_code = STAT_STATUS_NONE;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004475 return 0;
4476 }
4477
4478 first_param = temp->str;
4479 end_params = temp->str + reql;
4480 cur_param = next_param = end_params;
4481 *end_params = '\0';
4482
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004483 appctx->ctx.stats.st_code = STAT_STATUS_NONE;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004484
4485 /*
4486 * Parse the parameters in reverse order to only store the last value.
4487 * From the html form, the backend and the action are at the end.
4488 */
4489 while (cur_param > first_param) {
4490 char *value;
4491 int poffset, plen;
4492
4493 cur_param--;
4494
4495 if ((*cur_param == '&') || (cur_param == first_param)) {
4496 reprocess_servers:
4497 /* Parse the key */
4498 poffset = (cur_param != first_param ? 1 : 0);
4499 plen = next_param - cur_param + (cur_param == first_param ? 1 : 0);
4500 if ((plen > 0) && (plen <= sizeof(key))) {
4501 strncpy(key, cur_param + poffset, plen);
4502 key[plen - 1] = '\0';
4503 } else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004504 appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004505 goto out;
4506 }
4507
4508 /* Parse the value */
4509 value = key;
4510 while (*value != '\0' && *value != '=') {
4511 value++;
4512 }
4513 if (*value == '=') {
4514 /* Ok, a value is found, we can mark the end of the key */
4515 *value++ = '\0';
4516 }
4517 if (url_decode(key) < 0 || url_decode(value) < 0)
4518 break;
4519
4520 /* Now we can check the key to see what to do */
4521 if (!px && (strcmp(key, "b") == 0)) {
4522 if ((px = findproxy(value, PR_CAP_BE)) == NULL) {
4523 /* the backend name is unknown or ambiguous (duplicate names) */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004524 appctx->ctx.stats.st_code = STAT_STATUS_ERRP;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004525 goto out;
4526 }
4527 }
4528 else if (!action && (strcmp(key, "action") == 0)) {
Willy Tarreaued7df902014-05-22 18:04:49 +02004529 if (strcmp(value, "ready") == 0) {
4530 action = ST_ADM_ACTION_READY;
4531 }
4532 else if (strcmp(value, "drain") == 0) {
4533 action = ST_ADM_ACTION_DRAIN;
4534 }
4535 else if (strcmp(value, "maint") == 0) {
4536 action = ST_ADM_ACTION_MAINT;
4537 }
4538 else if (strcmp(value, "shutdown") == 0) {
4539 action = ST_ADM_ACTION_SHUTDOWN;
4540 }
Willy Tarreau248a60e2014-05-23 14:59:48 +02004541 else if (strcmp(value, "dhlth") == 0) {
4542 action = ST_ADM_ACTION_DHLTH;
4543 }
4544 else if (strcmp(value, "ehlth") == 0) {
4545 action = ST_ADM_ACTION_EHLTH;
4546 }
4547 else if (strcmp(value, "hrunn") == 0) {
4548 action = ST_ADM_ACTION_HRUNN;
4549 }
4550 else if (strcmp(value, "hnolb") == 0) {
4551 action = ST_ADM_ACTION_HNOLB;
4552 }
4553 else if (strcmp(value, "hdown") == 0) {
4554 action = ST_ADM_ACTION_HDOWN;
4555 }
4556 else if (strcmp(value, "dagent") == 0) {
4557 action = ST_ADM_ACTION_DAGENT;
4558 }
4559 else if (strcmp(value, "eagent") == 0) {
4560 action = ST_ADM_ACTION_EAGENT;
4561 }
4562 else if (strcmp(value, "arunn") == 0) {
4563 action = ST_ADM_ACTION_ARUNN;
4564 }
4565 else if (strcmp(value, "adown") == 0) {
4566 action = ST_ADM_ACTION_ADOWN;
4567 }
Willy Tarreaued7df902014-05-22 18:04:49 +02004568 /* else these are the old supported methods */
4569 else if (strcmp(value, "disable") == 0) {
Willy Tarreau347a35d2013-11-22 17:51:09 +01004570 action = ST_ADM_ACTION_DISABLE;
4571 }
4572 else if (strcmp(value, "enable") == 0) {
4573 action = ST_ADM_ACTION_ENABLE;
4574 }
4575 else if (strcmp(value, "stop") == 0) {
4576 action = ST_ADM_ACTION_STOP;
4577 }
4578 else if (strcmp(value, "start") == 0) {
4579 action = ST_ADM_ACTION_START;
4580 }
Willy Tarreau347a35d2013-11-22 17:51:09 +01004581 else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004582 appctx->ctx.stats.st_code = STAT_STATUS_ERRP;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004583 goto out;
4584 }
4585 }
4586 else if (strcmp(key, "s") == 0) {
4587 if (!(px && action)) {
4588 /*
4589 * Indicates that we'll need to reprocess the parameters
4590 * as soon as backend and action are known
4591 */
4592 if (!reprocess) {
4593 st_cur_param = cur_param;
4594 st_next_param = next_param;
4595 }
4596 reprocess = 1;
4597 }
4598 else if ((sv = findserver(px, value)) != NULL) {
4599 switch (action) {
4600 case ST_ADM_ACTION_DISABLE:
Willy Tarreaufae3a7e2014-05-22 17:22:34 +02004601 if (!(sv->admin & SRV_ADMF_FMAINT)) {
Willy Tarreau347a35d2013-11-22 17:51:09 +01004602 altered_servers++;
4603 total_servers++;
Willy Tarreaufae3a7e2014-05-22 17:22:34 +02004604 srv_set_admin_flag(sv, SRV_ADMF_FMAINT);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004605 }
4606 break;
4607 case ST_ADM_ACTION_ENABLE:
Willy Tarreaufae3a7e2014-05-22 17:22:34 +02004608 if (sv->admin & SRV_ADMF_FMAINT) {
Willy Tarreau347a35d2013-11-22 17:51:09 +01004609 altered_servers++;
4610 total_servers++;
Willy Tarreaufae3a7e2014-05-22 17:22:34 +02004611 srv_clr_admin_flag(sv, SRV_ADMF_FMAINT);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004612 }
4613 break;
4614 case ST_ADM_ACTION_STOP:
Willy Tarreaufae3a7e2014-05-22 17:22:34 +02004615 if (!(sv->admin & SRV_ADMF_FDRAIN)) {
4616 srv_set_admin_flag(sv, SRV_ADMF_FDRAIN);
4617 altered_servers++;
4618 total_servers++;
4619 }
4620 break;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004621 case ST_ADM_ACTION_START:
Willy Tarreaufae3a7e2014-05-22 17:22:34 +02004622 if (sv->admin & SRV_ADMF_FDRAIN) {
4623 srv_clr_admin_flag(sv, SRV_ADMF_FDRAIN);
4624 altered_servers++;
4625 total_servers++;
4626 }
Willy Tarreau347a35d2013-11-22 17:51:09 +01004627 break;
Willy Tarreau248a60e2014-05-23 14:59:48 +02004628 case ST_ADM_ACTION_DHLTH:
4629 if (sv->check.state & CHK_ST_CONFIGURED) {
4630 sv->check.state &= ~CHK_ST_ENABLED;
4631 altered_servers++;
4632 total_servers++;
4633 }
4634 break;
4635 case ST_ADM_ACTION_EHLTH:
4636 if (sv->check.state & CHK_ST_CONFIGURED) {
4637 sv->check.state |= CHK_ST_ENABLED;
4638 altered_servers++;
4639 total_servers++;
4640 }
4641 break;
4642 case ST_ADM_ACTION_HRUNN:
4643 if (!(sv->track)) {
4644 sv->check.health = sv->check.rise + sv->check.fall - 1;
4645 srv_set_running(sv, "changed from Web interface");
4646 altered_servers++;
4647 total_servers++;
4648 }
4649 break;
4650 case ST_ADM_ACTION_HNOLB:
4651 if (!(sv->track)) {
4652 sv->check.health = sv->check.rise + sv->check.fall - 1;
4653 srv_set_stopping(sv, "changed from Web interface");
4654 altered_servers++;
4655 total_servers++;
4656 }
4657 break;
4658 case ST_ADM_ACTION_HDOWN:
4659 if (!(sv->track)) {
4660 sv->check.health = 0;
4661 srv_set_stopped(sv, "changed from Web interface");
4662 altered_servers++;
4663 total_servers++;
4664 }
4665 break;
4666 case ST_ADM_ACTION_DAGENT:
4667 if (sv->agent.state & CHK_ST_CONFIGURED) {
4668 sv->agent.state &= ~CHK_ST_ENABLED;
4669 altered_servers++;
4670 total_servers++;
4671 }
4672 break;
4673 case ST_ADM_ACTION_EAGENT:
4674 if (sv->agent.state & CHK_ST_CONFIGURED) {
4675 sv->agent.state |= CHK_ST_ENABLED;
4676 altered_servers++;
4677 total_servers++;
4678 }
4679 break;
4680 case ST_ADM_ACTION_ARUNN:
4681 if (sv->agent.state & CHK_ST_ENABLED) {
4682 sv->agent.health = sv->agent.rise + sv->agent.fall - 1;
4683 srv_set_running(sv, "changed from Web interface");
4684 altered_servers++;
4685 total_servers++;
4686 }
4687 break;
4688 case ST_ADM_ACTION_ADOWN:
4689 if (sv->agent.state & CHK_ST_ENABLED) {
4690 sv->agent.health = 0;
4691 srv_set_stopped(sv, "changed from Web interface");
4692 altered_servers++;
4693 total_servers++;
4694 }
4695 break;
Willy Tarreaued7df902014-05-22 18:04:49 +02004696 case ST_ADM_ACTION_READY:
4697 srv_adm_set_ready(sv);
4698 altered_servers++;
4699 total_servers++;
4700 break;
4701 case ST_ADM_ACTION_DRAIN:
4702 srv_adm_set_drain(sv);
4703 altered_servers++;
4704 total_servers++;
4705 break;
4706 case ST_ADM_ACTION_MAINT:
4707 srv_adm_set_maint(sv);
4708 altered_servers++;
4709 total_servers++;
4710 break;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004711 case ST_ADM_ACTION_SHUTDOWN:
4712 if (px->state != PR_STSTOPPED) {
Willy Tarreau87b09662015-04-03 00:22:06 +02004713 struct stream *sess, *sess_bck;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004714
4715 list_for_each_entry_safe(sess, sess_bck, &sv->actconns, by_srv)
4716 if (sess->srv_conn == sv)
Willy Tarreaue7dff022015-04-03 01:14:29 +02004717 stream_shutdown(sess, SF_ERR_KILLED);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004718
4719 altered_servers++;
4720 total_servers++;
4721 }
4722 break;
4723 }
4724 } else {
4725 /* the server name is unknown or ambiguous (duplicate names) */
4726 total_servers++;
4727 }
4728 }
4729 if (reprocess && px && action) {
4730 /* Now, we know the backend and the action chosen by the user.
4731 * We can safely restart from the first server parameter
4732 * to reprocess them
4733 */
4734 cur_param = st_cur_param;
4735 next_param = st_next_param;
4736 reprocess = 0;
4737 goto reprocess_servers;
4738 }
4739
4740 next_param = cur_param;
4741 }
4742 }
4743
4744 if (total_servers == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004745 appctx->ctx.stats.st_code = STAT_STATUS_NONE;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004746 }
4747 else if (altered_servers == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004748 appctx->ctx.stats.st_code = STAT_STATUS_ERRP;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004749 }
4750 else if (altered_servers == total_servers) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004751 appctx->ctx.stats.st_code = STAT_STATUS_DONE;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004752 }
4753 else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004754 appctx->ctx.stats.st_code = STAT_STATUS_PART;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004755 }
4756 out:
4757 return 1;
4758}
4759
4760
4761static int stats_send_http_headers(struct stream_interface *si)
4762{
Willy Tarreau87b09662015-04-03 00:22:06 +02004763 struct stream *s = si_strm(si);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004764 struct uri_auth *uri = s->be->uri_auth;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004765 struct appctx *appctx = objt_appctx(si->end);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004766
4767 chunk_printf(&trash,
Willy Tarreau8b8995f2014-04-24 22:51:54 +02004768 "HTTP/1.1 200 OK\r\n"
Willy Tarreau347a35d2013-11-22 17:51:09 +01004769 "Cache-Control: no-cache\r\n"
4770 "Connection: close\r\n"
4771 "Content-Type: %s\r\n",
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004772 (appctx->ctx.stats.flags & STAT_FMT_HTML) ? "text/html" : "text/plain");
Willy Tarreau347a35d2013-11-22 17:51:09 +01004773
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004774 if (uri->refresh > 0 && !(appctx->ctx.stats.flags & STAT_NO_REFRESH))
Willy Tarreau347a35d2013-11-22 17:51:09 +01004775 chunk_appendf(&trash, "Refresh: %d\r\n",
4776 uri->refresh);
4777
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004778 /* we don't send the CRLF in chunked mode, it will be sent with the first chunk's size */
4779
4780 if (appctx->ctx.stats.flags & STAT_CHUNKED)
4781 chunk_appendf(&trash, "Transfer-Encoding: chunked\r\n");
4782 else
4783 chunk_appendf(&trash, "\r\n");
Willy Tarreau347a35d2013-11-22 17:51:09 +01004784
Willy Tarreaueee5b512015-04-03 23:46:31 +02004785 s->txn->status = 200;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004786 s->logs.tv_request = now;
4787
Willy Tarreaubc18da12015-03-13 14:00:47 +01004788 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02004789 si_applet_cant_put(si);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004790 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01004791 }
Willy Tarreau347a35d2013-11-22 17:51:09 +01004792
4793 return 1;
4794}
4795
4796static int stats_send_http_redirect(struct stream_interface *si)
4797{
4798 char scope_txt[STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN];
Willy Tarreau87b09662015-04-03 00:22:06 +02004799 struct stream *s = si_strm(si);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004800 struct uri_auth *uri = s->be->uri_auth;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004801 struct appctx *appctx = objt_appctx(si->end);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004802
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004803 /* scope_txt = search pattern + search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
Willy Tarreau347a35d2013-11-22 17:51:09 +01004804 scope_txt[0] = 0;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004805 if (appctx->ctx.stats.scope_len) {
Willy Tarreau347a35d2013-11-22 17:51:09 +01004806 strcpy(scope_txt, STAT_SCOPE_PATTERN);
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004807 memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), bo_ptr(si_ob(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004808 scope_txt[strlen(STAT_SCOPE_PATTERN) + appctx->ctx.stats.scope_len] = 0;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004809 }
4810
4811 /* We don't want to land on the posted stats page because a refresh will
4812 * repost the data. We don't want this to happen on accident so we redirect
4813 * the browse to the stats page with a GET.
4814 */
4815 chunk_printf(&trash,
4816 "HTTP/1.1 303 See Other\r\n"
4817 "Cache-Control: no-cache\r\n"
4818 "Content-Type: text/plain\r\n"
4819 "Connection: close\r\n"
4820 "Location: %s;st=%s%s%s%s\r\n"
4821 "\r\n",
4822 uri->uri_prefix,
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004823 ((appctx->ctx.stats.st_code > STAT_STATUS_INIT) &&
4824 (appctx->ctx.stats.st_code < STAT_STATUS_SIZE) &&
4825 stat_status_codes[appctx->ctx.stats.st_code]) ?
4826 stat_status_codes[appctx->ctx.stats.st_code] :
Willy Tarreau347a35d2013-11-22 17:51:09 +01004827 stat_status_codes[STAT_STATUS_UNKN],
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004828 (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
4829 (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "",
Willy Tarreau347a35d2013-11-22 17:51:09 +01004830 scope_txt);
4831
Willy Tarreaueee5b512015-04-03 23:46:31 +02004832 s->txn->status = 303;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004833 s->logs.tv_request = now;
4834
Willy Tarreaubc18da12015-03-13 14:00:47 +01004835 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02004836 si_applet_cant_put(si);
Willy Tarreau347a35d2013-11-22 17:51:09 +01004837 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01004838 }
Willy Tarreau347a35d2013-11-22 17:51:09 +01004839
4840 return 1;
4841}
4842
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004843/* This I/O handler runs as an applet embedded in a stream interface. It is
4844 * used to send HTTP stats over a TCP socket. The mechanism is very simple.
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004845 * appctx->st0 contains the operation in progress (dump, done). The handler
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004846 * automatically unregisters itself once transfer is complete.
4847 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02004848static void http_stats_io_handler(struct appctx *appctx)
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004849{
Willy Tarreau00a37f02015-04-13 12:05:19 +02004850 struct stream_interface *si = appctx->owner;
Willy Tarreau87b09662015-04-03 00:22:06 +02004851 struct stream *s = si_strm(si);
Willy Tarreau2bb4a962014-11-28 11:11:05 +01004852 struct channel *req = si_oc(si);
4853 struct channel *res = si_ic(si);
Willy Tarreau55058a72012-11-21 08:27:21 +01004854
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004855 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
4856 goto out;
Willy Tarreau5e16cbc2012-11-24 14:54:13 +01004857
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004858 /* check that the output is not closed */
4859 if (res->flags & (CF_SHUTW|CF_SHUTW_NOW))
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004860 appctx->st0 = STAT_HTTP_DONE;
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004861
Willy Tarreau347a35d2013-11-22 17:51:09 +01004862 /* all states are processed in sequence */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004863 if (appctx->st0 == STAT_HTTP_HEAD) {
Willy Tarreau347a35d2013-11-22 17:51:09 +01004864 if (stats_send_http_headers(si)) {
Willy Tarreaueee5b512015-04-03 23:46:31 +02004865 if (s->txn->meth == HTTP_METH_HEAD)
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004866 appctx->st0 = STAT_HTTP_DONE;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004867 else
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004868 appctx->st0 = STAT_HTTP_DUMP;
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004869 }
Willy Tarreau347a35d2013-11-22 17:51:09 +01004870 }
4871
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004872 if (appctx->st0 == STAT_HTTP_DUMP) {
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004873 unsigned int prev_len = si_ib(si)->i;
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004874 unsigned int data_len;
4875 unsigned int last_len;
Willy Tarreaucce36482014-04-24 20:26:41 +02004876 unsigned int last_fwd = 0;
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004877
4878 if (appctx->ctx.stats.flags & STAT_CHUNKED) {
4879 /* One difficulty we're facing is that we must prevent
4880 * the input data from being automatically forwarded to
4881 * the output area. For this, we temporarily disable
4882 * forwarding on the channel.
4883 */
Willy Tarreau2bb4a962014-11-28 11:11:05 +01004884 last_fwd = si_ic(si)->to_forward;
4885 si_ic(si)->to_forward = 0;
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004886 chunk_printf(&trash, "\r\n000000\r\n");
Willy Tarreau2bb4a962014-11-28 11:11:05 +01004887 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02004888 si_applet_cant_put(si);
Willy Tarreau2bb4a962014-11-28 11:11:05 +01004889 si_ic(si)->to_forward = last_fwd;
Willy Tarreau828824a2015-04-19 17:20:03 +02004890 goto out;
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004891 }
4892 }
4893
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004894 data_len = si_ib(si)->i;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004895 if (stats_dump_stat_to_buffer(si, s->be->uri_auth))
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004896 appctx->st0 = STAT_HTTP_DONE;
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004897
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004898 last_len = si_ib(si)->i;
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004899
4900 /* Now we must either adjust or remove the chunk size. This is
4901 * not easy because the chunk size might wrap at the end of the
4902 * buffer, so we pretend we have nothing in the buffer, we write
4903 * the size, then restore the buffer's contents. Note that we can
4904 * only do that because no forwarding is scheduled on the stats
4905 * applet.
4906 */
4907 if (appctx->ctx.stats.flags & STAT_CHUNKED) {
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004908 si_ic(si)->total -= (last_len - prev_len);
4909 si_ib(si)->i -= (last_len - prev_len);
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004910
4911 if (last_len != data_len) {
4912 chunk_printf(&trash, "\r\n%06x\r\n", (last_len - data_len));
Willy Tarreaubc18da12015-03-13 14:00:47 +01004913 if (bi_putchk(si_ic(si), &trash) == -1)
Willy Tarreaufe127932015-04-21 19:23:39 +02004914 si_applet_cant_put(si);
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004915
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004916 si_ic(si)->total += (last_len - data_len);
4917 si_ib(si)->i += (last_len - data_len);
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004918 }
4919 /* now re-enable forwarding */
Willy Tarreau2bb4a962014-11-28 11:11:05 +01004920 channel_forward(si_ic(si), last_fwd);
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004921 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004922 }
Cyril Bonté70be45d2010-10-12 00:14:35 +02004923
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004924 if (appctx->st0 == STAT_HTTP_POST) {
Willy Tarreau347a35d2013-11-22 17:51:09 +01004925 if (stats_process_http_post(si))
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004926 appctx->st0 = STAT_HTTP_LAST;
Willy Tarreau2bb4a962014-11-28 11:11:05 +01004927 else if (si_oc(si)->flags & CF_SHUTR)
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004928 appctx->st0 = STAT_HTTP_DONE;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004929 }
4930
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004931 if (appctx->st0 == STAT_HTTP_LAST) {
Willy Tarreau347a35d2013-11-22 17:51:09 +01004932 if (stats_send_http_redirect(si))
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004933 appctx->st0 = STAT_HTTP_DONE;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004934 }
4935
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004936 if (appctx->st0 == STAT_HTTP_DONE) {
4937 if (appctx->ctx.stats.flags & STAT_CHUNKED) {
4938 chunk_printf(&trash, "\r\n0\r\n\r\n");
Willy Tarreaubc18da12015-03-13 14:00:47 +01004939 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02004940 si_applet_cant_put(si);
Willy Tarreau828824a2015-04-19 17:20:03 +02004941 goto out;
Willy Tarreaubc18da12015-03-13 14:00:47 +01004942 }
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004943 }
4944 /* eat the whole request */
Willy Tarreau4e4292b2014-11-28 12:18:45 +01004945 bo_skip(si_oc(si), si_ob(si)->o);
Willy Tarreauaf3cf702014-04-22 22:19:53 +02004946 res->flags |= CF_READ_NULL;
4947 si_shutr(si);
4948 }
Willy Tarreau347a35d2013-11-22 17:51:09 +01004949
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004950 if ((res->flags & CF_SHUTR) && (si->state == SI_ST_EST))
4951 si_shutw(si);
Willy Tarreau91861262007-10-17 17:06:05 +02004952
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004953 if (appctx->st0 == STAT_HTTP_DONE) {
Willy Tarreau96d44912013-11-22 12:25:24 +01004954 if ((req->flags & CF_SHUTW) && (si->state == SI_ST_EST)) {
4955 si_shutr(si);
4956 res->flags |= CF_READ_NULL;
4957 }
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004958 }
Willy Tarreau828824a2015-04-19 17:20:03 +02004959 out:
Willy Tarreaud4da1962015-04-20 01:31:23 +02004960 /* just to make gcc happy */ ;
Willy Tarreau91861262007-10-17 17:06:05 +02004961}
4962
Willy Tarreaud9bdcd52012-12-22 20:31:10 +01004963
Willy Tarreau909d5172012-11-26 03:04:41 +01004964static inline const char *get_conn_ctrl_name(const struct connection *conn)
4965{
Willy Tarreau3c728722014-01-23 13:50:42 +01004966 if (!conn_ctrl_ready(conn))
Willy Tarreau909d5172012-11-26 03:04:41 +01004967 return "NONE";
4968 return conn->ctrl->name;
4969}
4970
4971static inline const char *get_conn_xprt_name(const struct connection *conn)
4972{
4973 static char ptr[17];
4974
Willy Tarreauaad69382014-01-23 14:21:42 +01004975 if (!conn_xprt_ready(conn))
Willy Tarreau909d5172012-11-26 03:04:41 +01004976 return "NONE";
4977
4978 if (conn->xprt == &raw_sock)
4979 return "RAW";
4980
4981#ifdef USE_OPENSSL
4982 if (conn->xprt == &ssl_sock)
4983 return "SSL";
4984#endif
4985 snprintf(ptr, sizeof(ptr), "%p", conn->xprt);
4986 return ptr;
4987}
4988
4989static inline const char *get_conn_data_name(const struct connection *conn)
4990{
4991 static char ptr[17];
4992
4993 if (!conn->data)
4994 return "NONE";
4995
4996 if (conn->data == &sess_conn_cb)
4997 return "SESS";
4998
4999 if (conn->data == &si_conn_cb)
5000 return "STRM";
5001
5002 if (conn->data == &check_conn_cb)
5003 return "CHCK";
5004
5005 snprintf(ptr, sizeof(ptr), "%p", conn->data);
5006 return ptr;
5007}
5008
Willy Tarreau87b09662015-04-03 00:22:06 +02005009/* This function dumps a complete stream state onto the stream interface's
5010 * read buffer. The stream has to be set in sess->target. It returns
Willy Tarreau5ec29ff2011-02-13 15:27:22 +01005011 * 0 if the output buffer is full and it needs to be called again, otherwise
5012 * non-zero. It is designed to be called from stats_dump_sess_to_buffer() below.
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005013 */
Willy Tarreau87b09662015-04-03 00:22:06 +02005014static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct stream *sess)
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005015{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005016 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005017 struct tm tm;
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005018 extern const char *monthname[12];
5019 char pn[INET6_ADDRSTRLEN];
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005020 struct connection *conn;
Willy Tarreau284ddbf2013-12-01 20:45:00 +01005021 struct appctx *tmpctx;
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005022
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005023 chunk_reset(&trash);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005024
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005025 if (appctx->ctx.sess.section > 0 && appctx->ctx.sess.uid != sess->uniq_id) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005026 /* stream changed, no need to go any further */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005027 chunk_appendf(&trash, " *** session terminated while we were watching it ***\n");
Willy Tarreaubc18da12015-03-13 14:00:47 +01005028 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02005029 si_applet_cant_put(si);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005030 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01005031 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005032 appctx->ctx.sess.uid = 0;
5033 appctx->ctx.sess.section = 0;
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005034 return 1;
5035 }
5036
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005037 switch (appctx->ctx.sess.section) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005038 case 0: /* main status of the stream */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005039 appctx->ctx.sess.uid = sess->uniq_id;
5040 appctx->ctx.sess.section = 1;
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005041 /* fall through */
5042
5043 case 1:
Willy Tarreau55e4ecd2012-12-08 17:48:47 +01005044 get_localtime(sess->logs.accept_date.tv_sec, &tm);
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005045 chunk_appendf(&trash,
Willy Tarreau55e4ecd2012-12-08 17:48:47 +01005046 "%p: [%02d/%s/%04d:%02d:%02d:%02d.%06d] id=%u proto=%s",
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005047 sess,
Willy Tarreau55e4ecd2012-12-08 17:48:47 +01005048 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
5049 tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(sess->logs.accept_date.tv_usec),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005050 sess->uniq_id,
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005051 strm_li(sess) && strm_li(sess)->proto->name ? strm_li(sess)->proto->name : "?");
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005052
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005053 conn = objt_conn(strm_orig(sess));
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005054 switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005055 case AF_INET:
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005056 case AF_INET6:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005057 chunk_appendf(&trash, " source=%s:%d\n",
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005058 pn, get_host_port(&conn->addr.from));
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005059 break;
5060 case AF_UNIX:
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005061 chunk_appendf(&trash, " source=unix:%d\n", strm_li(sess)->luid);
Emeric Brun837ca522010-10-22 16:19:01 +02005062 break;
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005063 default:
5064 /* no more information to print right now */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005065 chunk_appendf(&trash, "\n");
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005066 break;
5067 }
5068
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005069 chunk_appendf(&trash,
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005070 " flags=0x%x, conn_retries=%d, srv_conn=%p, pend_pos=%p\n",
Willy Tarreauee28de02010-06-01 09:51:00 +02005071 sess->flags, sess->si[1].conn_retries, sess->srv_conn, sess->pend_pos);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005072
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005073 chunk_appendf(&trash,
Daniel Schultze90690c72012-03-23 10:53:36 -07005074 " frontend=%s (id=%u mode=%s), listener=%s (id=%u)",
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005075 strm_fe(sess)->id, strm_fe(sess)->uuid, strm_fe(sess)->mode ? "http" : "tcp",
5076 strm_li(sess) ? strm_li(sess)->name ? strm_li(sess)->name : "?" : "?",
5077 strm_li(sess) ? strm_li(sess)->luid : 0);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005078
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005079 if (conn)
5080 conn_get_to_addr(conn);
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005081
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005082 switch (conn ? addr_to_str(&conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
Daniel Schultze90690c72012-03-23 10:53:36 -07005083 case AF_INET:
5084 case AF_INET6:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005085 chunk_appendf(&trash, " addr=%s:%d\n",
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005086 pn, get_host_port(&conn->addr.to));
Daniel Schultze90690c72012-03-23 10:53:36 -07005087 break;
5088 case AF_UNIX:
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005089 chunk_appendf(&trash, " addr=unix:%d\n", strm_li(sess)->luid);
Daniel Schultze90690c72012-03-23 10:53:36 -07005090 break;
5091 default:
5092 /* no more information to print right now */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005093 chunk_appendf(&trash, "\n");
Daniel Schultze90690c72012-03-23 10:53:36 -07005094 break;
5095 }
5096
Willy Tarreau50943332011-09-02 17:33:05 +02005097 if (sess->be->cap & PR_CAP_BE)
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005098 chunk_appendf(&trash,
Daniel Schultze90690c72012-03-23 10:53:36 -07005099 " backend=%s (id=%u mode=%s)",
Willy Tarreau50943332011-09-02 17:33:05 +02005100 sess->be->id,
Daniel Schultze90690c72012-03-23 10:53:36 -07005101 sess->be->uuid, sess->be->mode ? "http" : "tcp");
5102 else
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005103 chunk_appendf(&trash, " backend=<NONE> (id=-1 mode=-)");
Daniel Schultze90690c72012-03-23 10:53:36 -07005104
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005105 conn = objt_conn(sess->si[1].end);
5106 if (conn)
5107 conn_get_from_addr(conn);
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005108
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005109 switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
Daniel Schultze90690c72012-03-23 10:53:36 -07005110 case AF_INET:
5111 case AF_INET6:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005112 chunk_appendf(&trash, " addr=%s:%d\n",
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005113 pn, get_host_port(&conn->addr.from));
Daniel Schultze90690c72012-03-23 10:53:36 -07005114 break;
5115 case AF_UNIX:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005116 chunk_appendf(&trash, " addr=unix\n");
Daniel Schultze90690c72012-03-23 10:53:36 -07005117 break;
5118 default:
5119 /* no more information to print right now */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005120 chunk_appendf(&trash, "\n");
Daniel Schultze90690c72012-03-23 10:53:36 -07005121 break;
5122 }
5123
5124 if (sess->be->cap & PR_CAP_BE)
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005125 chunk_appendf(&trash,
Daniel Schultze90690c72012-03-23 10:53:36 -07005126 " server=%s (id=%u)",
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005127 objt_server(sess->target) ? objt_server(sess->target)->id : "<none>",
5128 objt_server(sess->target) ? objt_server(sess->target)->puid : 0);
Willy Tarreau50943332011-09-02 17:33:05 +02005129 else
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005130 chunk_appendf(&trash, " server=<NONE> (id=-1)");
Daniel Schultze90690c72012-03-23 10:53:36 -07005131
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005132 if (conn)
5133 conn_get_to_addr(conn);
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005134
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005135 switch (conn ? addr_to_str(&conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
Daniel Schultze90690c72012-03-23 10:53:36 -07005136 case AF_INET:
5137 case AF_INET6:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005138 chunk_appendf(&trash, " addr=%s:%d\n",
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005139 pn, get_host_port(&conn->addr.to));
Daniel Schultze90690c72012-03-23 10:53:36 -07005140 break;
5141 case AF_UNIX:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005142 chunk_appendf(&trash, " addr=unix\n");
Daniel Schultze90690c72012-03-23 10:53:36 -07005143 break;
5144 default:
5145 /* no more information to print right now */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005146 chunk_appendf(&trash, "\n");
Daniel Schultze90690c72012-03-23 10:53:36 -07005147 break;
5148 }
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005149
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005150 chunk_appendf(&trash,
Willy Tarreau55e4ecd2012-12-08 17:48:47 +01005151 " task=%p (state=0x%02x nice=%d calls=%d exp=%s%s",
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005152 sess->task,
5153 sess->task->state,
5154 sess->task->nice, sess->task->calls,
5155 sess->task->expire ?
5156 tick_is_expired(sess->task->expire, now_ms) ? "<PAST>" :
5157 human_time(TICKS_TO_MS(sess->task->expire - now_ms),
5158 TICKS_TO_MS(1000)) : "<NEVER>",
5159 task_in_rq(sess->task) ? ", running" : "");
5160
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005161 chunk_appendf(&trash,
Willy Tarreau55e4ecd2012-12-08 17:48:47 +01005162 " age=%s)\n",
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005163 human_time(now.tv_sec - sess->logs.accept_date.tv_sec, 1));
5164
Willy Tarreaueee5b512015-04-03 23:46:31 +02005165 if (sess->txn)
5166 chunk_appendf(&trash,
Willy Tarreau98410192014-11-26 18:05:38 +01005167 " txn=%p flags=0x%x meth=%d status=%d req.st=%s rsp.st=%s waiting=%d\n",
Willy Tarreaueee5b512015-04-03 23:46:31 +02005168 sess->txn, sess->txn->flags, sess->txn->meth, sess->txn->status,
5169 http_msg_state_str(sess->txn->req.msg_state), http_msg_state_str(sess->txn->rsp.msg_state), !LIST_ISEMPTY(&sess->buffer_wait));
Willy Tarreau55e4ecd2012-12-08 17:48:47 +01005170
5171 chunk_appendf(&trash,
Willy Tarreau32e3c6a2013-10-11 19:34:20 +02005172 " si[0]=%p (state=%s flags=0x%02x endp0=%s:%p exp=%s, et=0x%03x)\n",
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005173 &sess->si[0],
Willy Tarreau55e4ecd2012-12-08 17:48:47 +01005174 si_state_str(sess->si[0].state),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005175 sess->si[0].flags,
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005176 obj_type_name(sess->si[0].end),
5177 obj_base_ptr(sess->si[0].end),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005178 sess->si[0].exp ?
5179 tick_is_expired(sess->si[0].exp, now_ms) ? "<PAST>" :
5180 human_time(TICKS_TO_MS(sess->si[0].exp - now_ms),
5181 TICKS_TO_MS(1000)) : "<NEVER>",
5182 sess->si[0].err_type);
5183
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005184 chunk_appendf(&trash,
Willy Tarreau32e3c6a2013-10-11 19:34:20 +02005185 " si[1]=%p (state=%s flags=0x%02x endp1=%s:%p exp=%s, et=0x%03x)\n",
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005186 &sess->si[1],
Willy Tarreau55e4ecd2012-12-08 17:48:47 +01005187 si_state_str(sess->si[1].state),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005188 sess->si[1].flags,
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005189 obj_type_name(sess->si[1].end),
5190 obj_base_ptr(sess->si[1].end),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005191 sess->si[1].exp ?
5192 tick_is_expired(sess->si[1].exp, now_ms) ? "<PAST>" :
5193 human_time(TICKS_TO_MS(sess->si[1].exp - now_ms),
5194 TICKS_TO_MS(1000)) : "<NEVER>",
5195 sess->si[1].err_type);
5196
Willy Tarreau284ddbf2013-12-01 20:45:00 +01005197 if ((conn = objt_conn(sess->si[0].end)) != NULL) {
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005198 chunk_appendf(&trash,
5199 " co0=%p ctrl=%s xprt=%s data=%s target=%s:%p\n",
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005200 conn,
5201 get_conn_ctrl_name(conn),
5202 get_conn_xprt_name(conn),
5203 get_conn_data_name(conn),
5204 obj_type_name(conn->target),
5205 obj_base_ptr(conn->target));
Willy Tarreau909d5172012-11-26 03:04:41 +01005206
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005207 chunk_appendf(&trash,
Willy Tarreau16f649c2014-01-25 19:10:48 +01005208 " flags=0x%08x fd=%d fd.state=%02x fd.cache=%d updt=%d\n",
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005209 conn->flags,
5210 conn->t.sock.fd,
Willy Tarreau69a41fa2014-01-20 11:02:59 +01005211 conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].state : 0,
Willy Tarreau15a4dec2014-01-20 11:09:39 +01005212 conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].cache : 0,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005213 conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].updated : 0);
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005214 }
Willy Tarreau284ddbf2013-12-01 20:45:00 +01005215 else if ((tmpctx = objt_appctx(sess->si[0].end)) != NULL) {
5216 chunk_appendf(&trash,
5217 " app0=%p st0=%d st1=%d st2=%d applet=%s\n",
5218 tmpctx,
5219 tmpctx->st0,
5220 tmpctx->st1,
5221 tmpctx->st2,
5222 tmpctx->applet->name);
5223 }
Willy Tarreaubc174aa2012-11-19 16:10:32 +01005224
Willy Tarreau284ddbf2013-12-01 20:45:00 +01005225 if ((conn = objt_conn(sess->si[1].end)) != NULL) {
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005226 chunk_appendf(&trash,
5227 " co1=%p ctrl=%s xprt=%s data=%s target=%s:%p\n",
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005228 conn,
5229 get_conn_ctrl_name(conn),
5230 get_conn_xprt_name(conn),
5231 get_conn_data_name(conn),
5232 obj_type_name(conn->target),
5233 obj_base_ptr(conn->target));
Willy Tarreau909d5172012-11-26 03:04:41 +01005234
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005235 chunk_appendf(&trash,
5236 " flags=0x%08x fd=%d fd_spec_e=%02x fd_spec_p=%d updt=%d\n",
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005237 conn->flags,
5238 conn->t.sock.fd,
Willy Tarreau69a41fa2014-01-20 11:02:59 +01005239 conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].state : 0,
Willy Tarreau15a4dec2014-01-20 11:09:39 +01005240 conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].cache : 0,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005241 conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].updated : 0);
Willy Tarreaucf644ed2013-09-29 17:19:56 +02005242 }
Willy Tarreau284ddbf2013-12-01 20:45:00 +01005243 else if ((tmpctx = objt_appctx(sess->si[1].end)) != NULL) {
5244 chunk_appendf(&trash,
5245 " app1=%p st0=%d st1=%d st2=%d applet=%s\n",
5246 tmpctx,
5247 tmpctx->st0,
5248 tmpctx->st1,
5249 tmpctx->st2,
5250 tmpctx->applet->name);
5251 }
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005252
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005253 chunk_appendf(&trash,
Willy Tarreau909d5172012-11-26 03:04:41 +01005254 " req=%p (f=0x%06x an=0x%x pipe=%d tofwd=%d total=%lld)\n"
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005255 " an_exp=%s",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005256 &sess->req,
5257 sess->req.flags, sess->req.analysers,
5258 sess->req.pipe ? sess->req.pipe->data : 0,
5259 sess->req.to_forward, sess->req.total,
5260 sess->req.analyse_exp ?
5261 human_time(TICKS_TO_MS(sess->req.analyse_exp - now_ms),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005262 TICKS_TO_MS(1000)) : "<NEVER>");
5263
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005264 chunk_appendf(&trash,
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005265 " rex=%s",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005266 sess->req.rex ?
5267 human_time(TICKS_TO_MS(sess->req.rex - now_ms),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005268 TICKS_TO_MS(1000)) : "<NEVER>");
5269
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005270 chunk_appendf(&trash,
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005271 " wex=%s\n"
Willy Tarreau909d5172012-11-26 03:04:41 +01005272 " buf=%p data=%p o=%d p=%d req.next=%d i=%d size=%d\n",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005273 sess->req.wex ?
5274 human_time(TICKS_TO_MS(sess->req.wex - now_ms),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005275 TICKS_TO_MS(1000)) : "<NEVER>",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005276 sess->req.buf,
5277 sess->req.buf->data, sess->req.buf->o,
5278 (int)(sess->req.buf->p - sess->req.buf->data),
Willy Tarreaueee5b512015-04-03 23:46:31 +02005279 sess->txn ? sess->txn->req.next : 0, sess->req.buf->i,
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005280 sess->req.buf->size);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005281
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005282 chunk_appendf(&trash,
Willy Tarreau909d5172012-11-26 03:04:41 +01005283 " res=%p (f=0x%06x an=0x%x pipe=%d tofwd=%d total=%lld)\n"
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005284 " an_exp=%s",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005285 &sess->res,
5286 sess->res.flags, sess->res.analysers,
5287 sess->res.pipe ? sess->res.pipe->data : 0,
5288 sess->res.to_forward, sess->res.total,
5289 sess->res.analyse_exp ?
5290 human_time(TICKS_TO_MS(sess->res.analyse_exp - now_ms),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005291 TICKS_TO_MS(1000)) : "<NEVER>");
5292
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005293 chunk_appendf(&trash,
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005294 " rex=%s",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005295 sess->res.rex ?
5296 human_time(TICKS_TO_MS(sess->res.rex - now_ms),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005297 TICKS_TO_MS(1000)) : "<NEVER>");
5298
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005299 chunk_appendf(&trash,
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005300 " wex=%s\n"
Willy Tarreau909d5172012-11-26 03:04:41 +01005301 " buf=%p data=%p o=%d p=%d rsp.next=%d i=%d size=%d\n",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005302 sess->res.wex ?
5303 human_time(TICKS_TO_MS(sess->res.wex - now_ms),
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005304 TICKS_TO_MS(1000)) : "<NEVER>",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005305 sess->res.buf,
5306 sess->res.buf->data, sess->res.buf->o,
5307 (int)(sess->res.buf->p - sess->res.buf->data),
Willy Tarreaueee5b512015-04-03 23:46:31 +02005308 sess->txn ? sess->txn->rsp.next : 0, sess->res.buf->i,
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005309 sess->res.buf->size);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005310
Willy Tarreaubc18da12015-03-13 14:00:47 +01005311 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02005312 si_applet_cant_put(si);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005313 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01005314 }
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005315
5316 /* use other states to dump the contents */
5317 }
5318 /* end of dump */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005319 appctx->ctx.sess.uid = 0;
5320 appctx->ctx.sess.section = 0;
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005321 return 1;
5322}
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005323
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005324static int stats_pats_list(struct stream_interface *si)
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005325{
5326 struct appctx *appctx = __objt_appctx(si->end);
5327
5328 switch (appctx->st2) {
5329 case STAT_ST_INIT:
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01005330 /* Display the column headers. If the message cannot be sent,
5331 * quit the fucntion with returning 0. The function is called
5332 * later and restart at the state "STAT_ST_INIT".
5333 */
5334 chunk_reset(&trash);
Thierry FOURNIER65ce6132014-03-20 11:42:45 +01005335 chunk_appendf(&trash, "# id (file) description\n");
Willy Tarreaubc18da12015-03-13 14:00:47 +01005336 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02005337 si_applet_cant_put(si);
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01005338 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01005339 }
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005340
5341 /* Now, we start the browsing of the references lists.
5342 * Note that the following call to LIST_ELEM return bad pointer. The only
5343 * avalaible field of this pointer is <list>. It is used with the function
5344 * pat_list_get_next() for retruning the first avalaible entry
5345 */
5346 appctx->ctx.map.ref = LIST_ELEM(&pattern_reference, struct pat_ref *, list);
5347 appctx->ctx.map.ref = pat_list_get_next(appctx->ctx.map.ref, &pattern_reference,
5348 appctx->ctx.map.display_flags);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005349 appctx->st2 = STAT_ST_LIST;
5350 /* fall through */
5351
5352 case STAT_ST_LIST:
5353 while (appctx->ctx.map.ref) {
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005354 chunk_reset(&trash);
5355
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005356 /* Build messages. If the reference is used by another category than
5357 * the listed categorie, display the information in the massage.
5358 */
Thierry FOURNIERf7e04e92014-03-20 11:45:47 +01005359 chunk_appendf(&trash, "%d (%s) %s\n", appctx->ctx.map.ref->unique_id,
Thierry FOURNIER0d6ba512014-02-11 03:31:34 +01005360 appctx->ctx.map.ref->reference ? appctx->ctx.map.ref->reference : "",
5361 appctx->ctx.map.ref->display);
Thierry FOURNIERaf5a29d2014-03-11 14:29:22 +01005362
Willy Tarreau2bb4a962014-11-28 11:11:05 +01005363 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005364 /* let's try again later from this stream. We add ourselves into
5365 * this stream's users so that it can remove us upon termination.
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005366 */
Willy Tarreaufe127932015-04-21 19:23:39 +02005367 si_applet_cant_put(si);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005368 return 0;
5369 }
5370
5371 /* get next list entry and check the end of the list */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005372 appctx->ctx.map.ref = pat_list_get_next(appctx->ctx.map.ref, &pattern_reference,
5373 appctx->ctx.map.display_flags);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005374 }
5375
5376 appctx->st2 = STAT_ST_FIN;
5377 /* fall through */
5378
5379 default:
5380 appctx->st2 = STAT_ST_FIN;
5381 return 1;
5382 }
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005383 return 0;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005384}
5385
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005386static int stats_map_lookup(struct stream_interface *si)
5387{
5388 struct appctx *appctx = __objt_appctx(si->end);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005389 struct sample sample;
5390 struct pattern *pat;
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005391 int match_method;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005392
5393 switch (appctx->st2) {
5394 case STAT_ST_INIT:
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005395 /* Init to the first entry. The list cannot be change */
Thierry FOURNIERc5959fd2014-01-20 14:29:33 +01005396 appctx->ctx.map.expr = LIST_ELEM(&appctx->ctx.map.ref->pat, struct pattern_expr *, list);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005397 appctx->ctx.map.expr = pat_expr_get_next(appctx->ctx.map.expr, &appctx->ctx.map.ref->pat);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005398 appctx->st2 = STAT_ST_LIST;
5399 /* fall through */
5400
5401 case STAT_ST_LIST:
5402 /* for each lookup type */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005403 while (appctx->ctx.map.expr) {
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005404 /* initialise chunk to build new message */
5405 chunk_reset(&trash);
5406
5407 /* execute pattern matching */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +01005408 sample.type = SMP_T_STR;
5409 sample.flags |= SMP_F_CONST;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005410 sample.data.str.len = appctx->ctx.map.chunk.len;
5411 sample.data.str.str = appctx->ctx.map.chunk.str;
Thierry FOURNIER5d344082014-01-27 14:19:53 +01005412 if (appctx->ctx.map.expr->pat_head->match &&
5413 sample_convert(&sample, appctx->ctx.map.expr->pat_head->expect_type))
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005414 pat = appctx->ctx.map.expr->pat_head->match(&sample, appctx->ctx.map.expr, 1);
5415 else
5416 pat = NULL;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005417
5418 /* build return message: set type of match */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005419 for (match_method=0; match_method<PAT_MATCH_NUM; match_method++)
5420 if (appctx->ctx.map.expr->pat_head->match == pat_match_fcts[match_method])
5421 break;
5422 if (match_method >= PAT_MATCH_NUM)
5423 chunk_appendf(&trash, "type=unknown(%p)", appctx->ctx.map.expr->pat_head->match);
5424 else
5425 chunk_appendf(&trash, "type=%s", pat_match_names[match_method]);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005426
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +02005427 /* case sensitive */
5428 if (appctx->ctx.map.expr->mflags & PAT_MF_IGNORE_CASE)
5429 chunk_appendf(&trash, ", case=insensitive");
5430 else
5431 chunk_appendf(&trash, ", case=sensitive");
5432
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005433 /* Display no match, and set default value */
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +01005434 if (!pat) {
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005435 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
5436 chunk_appendf(&trash, ", found=no");
5437 else
5438 chunk_appendf(&trash, ", match=no");
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005439 }
5440
5441 /* Display match and match info */
5442 else {
5443 /* display match */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005444 if (appctx->ctx.map.display_flags == PAT_REF_MAP)
5445 chunk_appendf(&trash, ", found=yes");
5446 else
5447 chunk_appendf(&trash, ", match=yes");
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005448
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +01005449 /* display index mode */
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +02005450 if (pat->sflags & PAT_SF_TREE)
Thierry FOURNIERb9903842014-03-11 18:48:17 +01005451 chunk_appendf(&trash, ", idx=tree");
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005452 else
Thierry FOURNIERb9903842014-03-11 18:48:17 +01005453 chunk_appendf(&trash, ", idx=list");
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005454
Thierry FOURNIER86db66a2014-03-11 18:37:58 +01005455 /* display pattern */
5456 if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
5457 if (pat->ref && pat->ref->pattern)
5458 chunk_appendf(&trash, ", key=\"%s\"", pat->ref->pattern);
5459 else
5460 chunk_appendf(&trash, ", key=unknown");
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005461 }
5462 else {
Thierry FOURNIER86db66a2014-03-11 18:37:58 +01005463 if (pat->ref && pat->ref->pattern)
5464 chunk_appendf(&trash, ", pattern=\"%s\"", pat->ref->pattern);
5465 else
5466 chunk_appendf(&trash, ", pattern=unknown");
5467 }
5468
5469 /* display return value */
5470 if (appctx->ctx.map.display_flags == PAT_REF_MAP) {
5471 if (pat->smp && pat->ref && pat->ref->sample)
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005472 chunk_appendf(&trash, ", value=\"%s\", type=\"%s\"",
Thierry FOURNIER86db66a2014-03-11 18:37:58 +01005473 pat->ref->sample, smp_to_type[pat->smp->type]);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005474 else
Thierry FOURNIER86db66a2014-03-11 18:37:58 +01005475 chunk_appendf(&trash, ", value=none");
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005476 }
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005477 }
5478
Thierry FOURNIERb9903842014-03-11 18:48:17 +01005479 chunk_appendf(&trash, "\n");
5480
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005481 /* display response */
Willy Tarreau2bb4a962014-11-28 11:11:05 +01005482 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005483 /* let's try again later from this stream. We add ourselves into
5484 * this stream's users so that it can remove us upon termination.
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005485 */
Willy Tarreaufe127932015-04-21 19:23:39 +02005486 si_applet_cant_put(si);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005487 return 0;
5488 }
5489
5490 /* get next entry */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005491 appctx->ctx.map.expr = pat_expr_get_next(appctx->ctx.map.expr,
5492 &appctx->ctx.map.ref->pat);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005493 }
5494
5495 appctx->st2 = STAT_ST_FIN;
5496 /* fall through */
5497
5498 default:
5499 appctx->st2 = STAT_ST_FIN;
5500 free(appctx->ctx.map.chunk.str);
5501 return 1;
5502 }
5503}
5504
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005505static int stats_pat_list(struct stream_interface *si)
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005506{
5507 struct appctx *appctx = __objt_appctx(si->end);
5508
5509 switch (appctx->st2) {
5510
5511 case STAT_ST_INIT:
5512 /* Init to the first entry. The list cannot be change */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005513 appctx->ctx.map.elt = LIST_NEXT(&appctx->ctx.map.ref->head,
5514 struct pat_ref_elt *, list);
5515 if (&appctx->ctx.map.elt->list == &appctx->ctx.map.ref->head)
5516 appctx->ctx.map.elt = NULL;
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005517 appctx->st2 = STAT_ST_LIST;
5518 /* fall through */
5519
5520 case STAT_ST_LIST:
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005521 while (appctx->ctx.map.elt) {
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005522 chunk_reset(&trash);
5523
5524 /* build messages */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005525 if (appctx->ctx.map.elt->sample)
Thierry FOURNIER9356c682014-01-28 15:55:37 +01005526 chunk_appendf(&trash, "%p %s %s\n",
5527 appctx->ctx.map.elt, appctx->ctx.map.elt->pattern,
5528 appctx->ctx.map.elt->sample);
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005529 else
Thierry FOURNIER9356c682014-01-28 15:55:37 +01005530 chunk_appendf(&trash, "%p %s\n",
5531 appctx->ctx.map.elt, appctx->ctx.map.elt->pattern);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005532
Willy Tarreau2bb4a962014-11-28 11:11:05 +01005533 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005534 /* let's try again later from this stream. We add ourselves into
5535 * this stream's users so that it can remove us upon termination.
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005536 */
Willy Tarreaufe127932015-04-21 19:23:39 +02005537 si_applet_cant_put(si);
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005538 return 0;
5539 }
5540
5541 /* get next list entry and check the end of the list */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005542 appctx->ctx.map.elt = LIST_NEXT(&appctx->ctx.map.elt->list,
5543 struct pat_ref_elt *, list);
5544 if (&appctx->ctx.map.elt->list == &appctx->ctx.map.ref->head)
Thierry FOURNIERc0e0d7b2013-12-11 16:55:52 +01005545 break;
5546 }
5547
5548 appctx->st2 = STAT_ST_FIN;
5549 /* fall through */
5550
5551 default:
5552 appctx->st2 = STAT_ST_FIN;
5553 return 1;
5554 }
5555}
5556
Willy Tarreau87b09662015-04-03 00:22:06 +02005557/* This function dumps all streams' states onto the stream interface's
Willy Tarreau306f8302013-07-08 15:53:06 +02005558 * read buffer. It returns 0 if the output buffer is full and it needs
Willy Tarreau5ec29ff2011-02-13 15:27:22 +01005559 * to be called again, otherwise non-zero. It is designed to be called
5560 * from stats_dump_sess_to_buffer() below.
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005561 */
Simon Horman9bd2c732011-06-15 15:18:44 +09005562static int stats_dump_sess_to_buffer(struct stream_interface *si)
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005563{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005564 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005565 struct connection *conn;
5566
Willy Tarreau2bb4a962014-11-28 11:11:05 +01005567 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005568 /* If we're forced to shut down, we might have to remove our
Willy Tarreau87b09662015-04-03 00:22:06 +02005569 * reference to the last stream being dumped.
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005570 */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005571 if (appctx->st2 == STAT_ST_LIST) {
5572 if (!LIST_ISEMPTY(&appctx->ctx.sess.bref.users)) {
5573 LIST_DEL(&appctx->ctx.sess.bref.users);
5574 LIST_INIT(&appctx->ctx.sess.bref.users);
Willy Tarreaufd3828e2009-02-22 15:17:24 +01005575 }
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005576 }
Willy Tarreau7e72a8f2009-10-03 23:55:14 +02005577 return 1;
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005578 }
5579
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005580 chunk_reset(&trash);
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005581
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005582 switch (appctx->st2) {
Willy Tarreau295a8372011-03-10 11:25:07 +01005583 case STAT_ST_INIT:
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005584 /* the function had not been called yet, let's prepare the
Willy Tarreau87b09662015-04-03 00:22:06 +02005585 * buffer for a response. We initialize the current stream
Willy Tarreaufd3828e2009-02-22 15:17:24 +01005586 * pointer to the first in the global list. When a target
Willy Tarreau87b09662015-04-03 00:22:06 +02005587 * stream is being destroyed, it is responsible for updating
Willy Tarreaufd3828e2009-02-22 15:17:24 +01005588 * this pointer. We know we have reached the end when this
Willy Tarreau87b09662015-04-03 00:22:06 +02005589 * pointer points back to the head of the streams list.
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005590 */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005591 LIST_INIT(&appctx->ctx.sess.bref.users);
Willy Tarreau87b09662015-04-03 00:22:06 +02005592 appctx->ctx.sess.bref.ref = streams.n;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005593 appctx->st2 = STAT_ST_LIST;
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005594 /* fall through */
5595
Willy Tarreau295a8372011-03-10 11:25:07 +01005596 case STAT_ST_LIST:
Willy Tarreau87b09662015-04-03 00:22:06 +02005597 /* first, let's detach the back-ref from a possible previous stream */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005598 if (!LIST_ISEMPTY(&appctx->ctx.sess.bref.users)) {
5599 LIST_DEL(&appctx->ctx.sess.bref.users);
5600 LIST_INIT(&appctx->ctx.sess.bref.users);
Willy Tarreaufd3828e2009-02-22 15:17:24 +01005601 }
5602
5603 /* and start from where we stopped */
Willy Tarreau87b09662015-04-03 00:22:06 +02005604 while (appctx->ctx.sess.bref.ref != &streams) {
Cyril Bontéacd7d632010-11-01 19:26:02 +01005605 char pn[INET6_ADDRSTRLEN];
Willy Tarreau87b09662015-04-03 00:22:06 +02005606 struct stream *curr_sess;
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005607
Willy Tarreau87b09662015-04-03 00:22:06 +02005608 curr_sess = LIST_ELEM(appctx->ctx.sess.bref.ref, struct stream *, list);
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005609
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005610 if (appctx->ctx.sess.target) {
5611 if (appctx->ctx.sess.target != (void *)-1 && appctx->ctx.sess.target != curr_sess)
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005612 goto next_sess;
5613
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005614 LIST_ADDQ(&curr_sess->back_refs, &appctx->ctx.sess.bref.users);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005615 /* call the proper dump() function and return if we're missing space */
Willy Tarreau76153662012-11-26 01:16:39 +01005616 if (!stats_dump_full_sess_to_buffer(si, curr_sess))
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005617 return 0;
5618
Willy Tarreau87b09662015-04-03 00:22:06 +02005619 /* stream dump complete */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005620 LIST_DEL(&appctx->ctx.sess.bref.users);
5621 LIST_INIT(&appctx->ctx.sess.bref.users);
5622 if (appctx->ctx.sess.target != (void *)-1) {
5623 appctx->ctx.sess.target = NULL;
Willy Tarreau76153662012-11-26 01:16:39 +01005624 break;
5625 }
5626 else
5627 goto next_sess;
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005628 }
5629
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005630 chunk_appendf(&trash,
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005631 "%p: proto=%s",
5632 curr_sess,
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005633 strm_li(curr_sess)->proto->name);
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005634
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005635
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005636 conn = objt_conn(strm_orig(curr_sess));
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005637 switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
Willy Tarreau631f01c2011-09-05 00:36:48 +02005638 case AF_INET:
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005639 case AF_INET6:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005640 chunk_appendf(&trash,
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005641 " src=%s:%d fe=%s be=%s srv=%s",
5642 pn,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005643 get_host_port(&conn->addr.from),
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005644 strm_fe(curr_sess)->id,
Willy Tarreau50943332011-09-02 17:33:05 +02005645 (curr_sess->be->cap & PR_CAP_BE) ? curr_sess->be->id : "<NONE>",
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005646 objt_server(curr_sess->target) ? objt_server(curr_sess->target)->id : "<none>"
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005647 );
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005648 break;
5649 case AF_UNIX:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005650 chunk_appendf(&trash,
Emeric Brun837ca522010-10-22 16:19:01 +02005651 " src=unix:%d fe=%s be=%s srv=%s",
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005652 strm_li(curr_sess)->luid,
5653 strm_fe(curr_sess)->id,
Willy Tarreau50943332011-09-02 17:33:05 +02005654 (curr_sess->be->cap & PR_CAP_BE) ? curr_sess->be->id : "<NONE>",
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005655 objt_server(curr_sess->target) ? objt_server(curr_sess->target)->id : "<none>"
Emeric Brun837ca522010-10-22 16:19:01 +02005656 );
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005657 break;
5658 }
5659
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005660 chunk_appendf(&trash,
Willy Tarreau65671ab2009-10-04 14:24:59 +02005661 " ts=%02x age=%s calls=%d",
5662 curr_sess->task->state,
Willy Tarreau3884cba2009-03-28 17:54:35 +01005663 human_time(now.tv_sec - curr_sess->logs.tv_accept.tv_sec, 1),
5664 curr_sess->task->calls);
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005665
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005666 chunk_appendf(&trash,
Willy Tarreau02d6cfc2012-03-01 18:19:58 +01005667 " rq[f=%06xh,i=%d,an=%02xh,rx=%s",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005668 curr_sess->req.flags,
5669 curr_sess->req.buf->i,
5670 curr_sess->req.analysers,
5671 curr_sess->req.rex ?
5672 human_time(TICKS_TO_MS(curr_sess->req.rex - now_ms),
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005673 TICKS_TO_MS(1000)) : "");
5674
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005675 chunk_appendf(&trash,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005676 ",wx=%s",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005677 curr_sess->req.wex ?
5678 human_time(TICKS_TO_MS(curr_sess->req.wex - now_ms),
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005679 TICKS_TO_MS(1000)) : "");
5680
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005681 chunk_appendf(&trash,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005682 ",ax=%s]",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005683 curr_sess->req.analyse_exp ?
5684 human_time(TICKS_TO_MS(curr_sess->req.analyse_exp - now_ms),
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005685 TICKS_TO_MS(1000)) : "");
5686
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005687 chunk_appendf(&trash,
Willy Tarreau02d6cfc2012-03-01 18:19:58 +01005688 " rp[f=%06xh,i=%d,an=%02xh,rx=%s",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005689 curr_sess->res.flags,
5690 curr_sess->res.buf->i,
5691 curr_sess->res.analysers,
5692 curr_sess->res.rex ?
5693 human_time(TICKS_TO_MS(curr_sess->res.rex - now_ms),
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005694 TICKS_TO_MS(1000)) : "");
5695
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005696 chunk_appendf(&trash,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005697 ",wx=%s",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005698 curr_sess->res.wex ?
5699 human_time(TICKS_TO_MS(curr_sess->res.wex - now_ms),
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005700 TICKS_TO_MS(1000)) : "");
5701
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005702 chunk_appendf(&trash,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005703 ",ax=%s]",
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005704 curr_sess->res.analyse_exp ?
5705 human_time(TICKS_TO_MS(curr_sess->res.analyse_exp - now_ms),
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005706 TICKS_TO_MS(1000)) : "");
5707
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005708 conn = objt_conn(curr_sess->si[0].end);
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005709 chunk_appendf(&trash,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005710 " s0=[%d,%1xh,fd=%d,ex=%s]",
5711 curr_sess->si[0].state,
5712 curr_sess->si[0].flags,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005713 conn ? conn->t.sock.fd : -1,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005714 curr_sess->si[0].exp ?
5715 human_time(TICKS_TO_MS(curr_sess->si[0].exp - now_ms),
5716 TICKS_TO_MS(1000)) : "");
5717
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005718 conn = objt_conn(curr_sess->si[1].end);
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005719 chunk_appendf(&trash,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005720 " s1=[%d,%1xh,fd=%d,ex=%s]",
5721 curr_sess->si[1].state,
5722 curr_sess->si[1].flags,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02005723 conn ? conn->t.sock.fd : -1,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005724 curr_sess->si[1].exp ?
5725 human_time(TICKS_TO_MS(curr_sess->si[1].exp - now_ms),
5726 TICKS_TO_MS(1000)) : "");
5727
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005728 chunk_appendf(&trash,
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005729 " exp=%s",
5730 curr_sess->task->expire ?
5731 human_time(TICKS_TO_MS(curr_sess->task->expire - now_ms),
5732 TICKS_TO_MS(1000)) : "");
Willy Tarreau4726f532009-03-07 17:25:21 +01005733 if (task_in_rq(curr_sess->task))
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005734 chunk_appendf(&trash, " run(nice=%d)", curr_sess->task->nice);
Willy Tarreauc6dcad62009-03-29 00:18:14 +01005735
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005736 chunk_appendf(&trash, "\n");
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005737
Willy Tarreau2bb4a962014-11-28 11:11:05 +01005738 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005739 /* let's try again later from this stream. We add ourselves into
5740 * this stream's users so that it can remove us upon termination.
Willy Tarreaufd3828e2009-02-22 15:17:24 +01005741 */
Willy Tarreaufe127932015-04-21 19:23:39 +02005742 si_applet_cant_put(si);
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005743 LIST_ADDQ(&curr_sess->back_refs, &appctx->ctx.sess.bref.users);
Willy Tarreau7e72a8f2009-10-03 23:55:14 +02005744 return 0;
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005745 }
5746
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005747 next_sess:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005748 appctx->ctx.sess.bref.ref = curr_sess->list.n;
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005749 }
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005750
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005751 if (appctx->ctx.sess.target && appctx->ctx.sess.target != (void *)-1) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005752 /* specified stream not found */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005753 if (appctx->ctx.sess.section > 0)
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005754 chunk_appendf(&trash, " *** session terminated while we were watching it ***\n");
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005755 else
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005756 chunk_appendf(&trash, "Session not found.\n");
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005757
Willy Tarreaubc18da12015-03-13 14:00:47 +01005758 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02005759 si_applet_cant_put(si);
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005760 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01005761 }
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005762
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005763 appctx->ctx.sess.target = NULL;
5764 appctx->ctx.sess.uid = 0;
Willy Tarreau66dc20a2010-03-05 17:53:32 +01005765 return 1;
5766 }
5767
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005768 appctx->st2 = STAT_ST_FIN;
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005769 /* fall through */
5770
5771 default:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005772 appctx->st2 = STAT_ST_FIN;
Willy Tarreau7e72a8f2009-10-03 23:55:14 +02005773 return 1;
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005774 }
Emeric Brun1e029aa2010-09-23 18:12:53 +02005775}
5776
Willy Tarreau5f9a8772012-11-26 02:22:40 +01005777/* This is called when the stream interface is closed. For instance, upon an
5778 * external abort, we won't call the i/o handler anymore so we may need to
Willy Tarreau87b09662015-04-03 00:22:06 +02005779 * remove back references to the stream currently being dumped.
Willy Tarreau5f9a8772012-11-26 02:22:40 +01005780 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02005781static void cli_release_handler(struct appctx *appctx)
Willy Tarreau5f9a8772012-11-26 02:22:40 +01005782{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005783 if (appctx->st0 == STAT_CLI_O_SESS && appctx->st2 == STAT_ST_LIST) {
5784 if (!LIST_ISEMPTY(&appctx->ctx.sess.bref.users))
5785 LIST_DEL(&appctx->ctx.sess.bref.users);
Willy Tarreau5f9a8772012-11-26 02:22:40 +01005786 }
Thierry FOURNIER364cfdf2014-01-29 19:08:49 +01005787 else if (appctx->st0 == STAT_CLI_PRINT_FREE) {
5788 free(appctx->ctx.cli.err);
5789 }
Thierry FOURNIER1e00d382014-02-11 11:31:40 +01005790 else if (appctx->st0 == STAT_CLI_O_MLOOK) {
5791 free(appctx->ctx.map.chunk.str);
5792 }
Willy Tarreau5f9a8772012-11-26 02:22:40 +01005793}
5794
Willy Tarreau20e99322013-04-13 09:22:25 +02005795/* This function is used to either dump tables states (when action is set
5796 * to STAT_CLI_O_TAB) or clear tables (when action is STAT_CLI_O_CLR).
Willy Tarreau20e99322013-04-13 09:22:25 +02005797 * It returns 0 if the output buffer is full and it needs to be called
5798 * again, otherwise non-zero.
Willy Tarreau69f58c82010-07-12 17:55:33 +02005799 */
Willy Tarreau20e99322013-04-13 09:22:25 +02005800static int stats_table_request(struct stream_interface *si, int action)
Willy Tarreau69f58c82010-07-12 17:55:33 +02005801{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005802 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreau87b09662015-04-03 00:22:06 +02005803 struct stream *s = si_strm(si);
Willy Tarreau69f58c82010-07-12 17:55:33 +02005804 struct ebmb_node *eb;
5805 int dt;
Willy Tarreau44455022012-12-05 23:01:12 +01005806 int skip_entry;
Willy Tarreau20e99322013-04-13 09:22:25 +02005807 int show = action == STAT_CLI_O_TAB;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005808
5809 /*
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005810 * We have 3 possible states in appctx->st2 :
Willy Tarreau295a8372011-03-10 11:25:07 +01005811 * - STAT_ST_INIT : the first call
5812 * - STAT_ST_INFO : the proxy pointer points to the next table to
Willy Tarreau69f58c82010-07-12 17:55:33 +02005813 * dump, the entry pointer is NULL ;
Willy Tarreau295a8372011-03-10 11:25:07 +01005814 * - STAT_ST_LIST : the proxy pointer points to the current table
Willy Tarreau69f58c82010-07-12 17:55:33 +02005815 * and the entry pointer points to the next entry to be dumped,
5816 * and the refcount on the next entry is held ;
Willy Tarreau295a8372011-03-10 11:25:07 +01005817 * - STAT_ST_END : nothing left to dump, the buffer may contain some
Willy Tarreau69f58c82010-07-12 17:55:33 +02005818 * data though.
5819 */
5820
Willy Tarreau2bb4a962014-11-28 11:11:05 +01005821 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
Willy Tarreau69f58c82010-07-12 17:55:33 +02005822 /* in case of abort, remove any refcount we might have set on an entry */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005823 if (appctx->st2 == STAT_ST_LIST) {
5824 appctx->ctx.table.entry->ref_cnt--;
5825 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Willy Tarreauf6efda12010-08-03 20:34:06 +02005826 }
Willy Tarreau69f58c82010-07-12 17:55:33 +02005827 return 1;
5828 }
5829
Willy Tarreau19d14ef2012-10-29 16:51:55 +01005830 chunk_reset(&trash);
Willy Tarreau69f58c82010-07-12 17:55:33 +02005831
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005832 while (appctx->st2 != STAT_ST_FIN) {
5833 switch (appctx->st2) {
Willy Tarreau295a8372011-03-10 11:25:07 +01005834 case STAT_ST_INIT:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005835 appctx->ctx.table.proxy = appctx->ctx.table.target;
5836 if (!appctx->ctx.table.proxy)
5837 appctx->ctx.table.proxy = proxy;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005838
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005839 appctx->ctx.table.entry = NULL;
5840 appctx->st2 = STAT_ST_INFO;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005841 break;
5842
Willy Tarreau295a8372011-03-10 11:25:07 +01005843 case STAT_ST_INFO:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005844 if (!appctx->ctx.table.proxy ||
5845 (appctx->ctx.table.target &&
5846 appctx->ctx.table.proxy != appctx->ctx.table.target)) {
5847 appctx->st2 = STAT_ST_END;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005848 break;
5849 }
5850
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005851 if (appctx->ctx.table.proxy->table.size) {
5852 if (show && !stats_dump_table_head_to_buffer(&trash, si, appctx->ctx.table.proxy,
5853 appctx->ctx.table.target))
Willy Tarreau69f58c82010-07-12 17:55:33 +02005854 return 0;
5855
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005856 if (appctx->ctx.table.target &&
Willy Tarreaud0d8da92015-04-04 02:10:38 +02005857 strm_li(s)->bind_conf->level >= ACCESS_LVL_OPER) {
Willy Tarreau69f58c82010-07-12 17:55:33 +02005858 /* dump entries only if table explicitly requested */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005859 eb = ebmb_first(&appctx->ctx.table.proxy->table.keys);
Willy Tarreau69f58c82010-07-12 17:55:33 +02005860 if (eb) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005861 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
5862 appctx->ctx.table.entry->ref_cnt++;
5863 appctx->st2 = STAT_ST_LIST;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005864 break;
5865 }
5866 }
5867 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005868 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005869 break;
5870
Willy Tarreau295a8372011-03-10 11:25:07 +01005871 case STAT_ST_LIST:
Willy Tarreau44455022012-12-05 23:01:12 +01005872 skip_entry = 0;
Simon Hormanc88b8872011-06-15 15:18:49 +09005873
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005874 if (appctx->ctx.table.data_type >= 0) {
Willy Tarreau4f3f01f2010-07-18 11:46:20 +02005875 /* we're filtering on some data contents */
5876 void *ptr;
5877 long long data;
5878
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005879 dt = appctx->ctx.table.data_type;
5880 ptr = stktable_data_ptr(&appctx->ctx.table.proxy->table,
5881 appctx->ctx.table.entry,
Willy Tarreau4f3f01f2010-07-18 11:46:20 +02005882 dt);
5883
5884 data = 0;
5885 switch (stktable_data_types[dt].std_type) {
5886 case STD_T_SINT:
5887 data = stktable_data_cast(ptr, std_t_sint);
5888 break;
5889 case STD_T_UINT:
5890 data = stktable_data_cast(ptr, std_t_uint);
5891 break;
5892 case STD_T_ULL:
5893 data = stktable_data_cast(ptr, std_t_ull);
5894 break;
5895 case STD_T_FRQP:
5896 data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005897 appctx->ctx.table.proxy->table.data_arg[dt].u);
Willy Tarreau4f3f01f2010-07-18 11:46:20 +02005898 break;
5899 }
5900
5901 /* skip the entry if the data does not match the test and the value */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005902 if ((data < appctx->ctx.table.value &&
5903 (appctx->ctx.table.data_op == STD_OP_EQ ||
5904 appctx->ctx.table.data_op == STD_OP_GT ||
5905 appctx->ctx.table.data_op == STD_OP_GE)) ||
5906 (data == appctx->ctx.table.value &&
5907 (appctx->ctx.table.data_op == STD_OP_NE ||
5908 appctx->ctx.table.data_op == STD_OP_GT ||
5909 appctx->ctx.table.data_op == STD_OP_LT)) ||
5910 (data > appctx->ctx.table.value &&
5911 (appctx->ctx.table.data_op == STD_OP_EQ ||
5912 appctx->ctx.table.data_op == STD_OP_LT ||
5913 appctx->ctx.table.data_op == STD_OP_LE)))
Willy Tarreau44455022012-12-05 23:01:12 +01005914 skip_entry = 1;
Willy Tarreau4f3f01f2010-07-18 11:46:20 +02005915 }
5916
Simon Hormanc88b8872011-06-15 15:18:49 +09005917 if (show && !skip_entry &&
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005918 !stats_dump_table_entry_to_buffer(&trash, si, appctx->ctx.table.proxy,
5919 appctx->ctx.table.entry))
Simon Hormand9366582011-06-15 15:18:45 +09005920 return 0;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005921
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005922 appctx->ctx.table.entry->ref_cnt--;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005923
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005924 eb = ebmb_next(&appctx->ctx.table.entry->key);
Willy Tarreau69f58c82010-07-12 17:55:33 +02005925 if (eb) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005926 struct stksess *old = appctx->ctx.table.entry;
5927 appctx->ctx.table.entry = ebmb_entry(eb, struct stksess, key);
Willy Tarreau8fa52f42012-01-09 11:50:03 +01005928 if (show)
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005929 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, old);
5930 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
5931 stksess_kill(&appctx->ctx.table.proxy->table, old);
5932 appctx->ctx.table.entry->ref_cnt++;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005933 break;
5934 }
5935
Simon Hormanc88b8872011-06-15 15:18:49 +09005936
5937 if (show)
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005938 stksess_kill_if_expired(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
5939 else if (!skip_entry && !appctx->ctx.table.entry->ref_cnt)
5940 stksess_kill(&appctx->ctx.table.proxy->table, appctx->ctx.table.entry);
Simon Hormanc88b8872011-06-15 15:18:49 +09005941
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005942 appctx->ctx.table.proxy = appctx->ctx.table.proxy->next;
5943 appctx->st2 = STAT_ST_INFO;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005944 break;
5945
Willy Tarreau295a8372011-03-10 11:25:07 +01005946 case STAT_ST_END:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01005947 appctx->st2 = STAT_ST_FIN;
Willy Tarreau69f58c82010-07-12 17:55:33 +02005948 break;
5949 }
5950 }
5951 return 1;
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01005952}
5953
Willy Tarreaud426a182010-03-05 14:58:26 +01005954/* print a line of text buffer (limited to 70 bytes) to <out>. The format is :
Willy Tarreau74808cb2009-03-04 15:53:18 +01005955 * <2 spaces> <offset=5 digits> <space or plus> <space> <70 chars max> <\n>
5956 * which is 60 chars per line. Non-printable chars \t, \n, \r and \e are
5957 * encoded in C format. Other non-printable chars are encoded "\xHH". Original
5958 * lines are respected within the limit of 70 output chars. Lines that are
5959 * continuation of a previous truncated line begin with "+" instead of " "
5960 * after the offset. The new pointer is returned.
5961 */
Willy Tarreaud426a182010-03-05 14:58:26 +01005962static int dump_text_line(struct chunk *out, const char *buf, int bsize, int len,
5963 int *line, int ptr)
Willy Tarreau74808cb2009-03-04 15:53:18 +01005964{
5965 int end;
5966 unsigned char c;
5967
5968 end = out->len + 80;
Krzysztof Piotr Oledzki78abe612009-09-27 13:23:20 +02005969 if (end > out->size)
Willy Tarreau74808cb2009-03-04 15:53:18 +01005970 return ptr;
5971
Willy Tarreau77804732012-10-29 16:14:26 +01005972 chunk_appendf(out, " %05d%c ", ptr, (ptr == *line) ? ' ' : '+');
Willy Tarreau74808cb2009-03-04 15:53:18 +01005973
Willy Tarreaud426a182010-03-05 14:58:26 +01005974 while (ptr < len && ptr < bsize) {
5975 c = buf[ptr];
Willy Tarreau787bbd92009-03-12 08:18:33 +01005976 if (isprint(c) && isascii(c) && c != '\\') {
Willy Tarreau74808cb2009-03-04 15:53:18 +01005977 if (out->len > end - 2)
5978 break;
5979 out->str[out->len++] = c;
Willy Tarreau787bbd92009-03-12 08:18:33 +01005980 } else if (c == '\t' || c == '\n' || c == '\r' || c == '\e' || c == '\\') {
Willy Tarreau74808cb2009-03-04 15:53:18 +01005981 if (out->len > end - 3)
5982 break;
5983 out->str[out->len++] = '\\';
5984 switch (c) {
5985 case '\t': c = 't'; break;
5986 case '\n': c = 'n'; break;
5987 case '\r': c = 'r'; break;
5988 case '\e': c = 'e'; break;
Willy Tarreau787bbd92009-03-12 08:18:33 +01005989 case '\\': c = '\\'; break;
Willy Tarreau74808cb2009-03-04 15:53:18 +01005990 }
5991 out->str[out->len++] = c;
5992 } else {
5993 if (out->len > end - 5)
5994 break;
5995 out->str[out->len++] = '\\';
5996 out->str[out->len++] = 'x';
5997 out->str[out->len++] = hextab[(c >> 4) & 0xF];
5998 out->str[out->len++] = hextab[c & 0xF];
5999 }
Willy Tarreaud426a182010-03-05 14:58:26 +01006000 if (buf[ptr++] == '\n') {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006001 /* we had a line break, let's return now */
6002 out->str[out->len++] = '\n';
6003 *line = ptr;
6004 return ptr;
6005 }
6006 }
6007 /* we have an incomplete line, we return it as-is */
6008 out->str[out->len++] = '\n';
6009 return ptr;
6010}
6011
Willy Tarreauf7bc57c2012-10-03 00:19:48 +02006012/* This function dumps all captured errors onto the stream interface's
Willy Tarreau306f8302013-07-08 15:53:06 +02006013 * read buffer. It returns 0 if the output buffer is full and it needs
Willy Tarreau5ec29ff2011-02-13 15:27:22 +01006014 * to be called again, otherwise non-zero.
Willy Tarreau74808cb2009-03-04 15:53:18 +01006015 */
Simon Horman9bd2c732011-06-15 15:18:44 +09006016static int stats_dump_errors_to_buffer(struct stream_interface *si)
Willy Tarreau74808cb2009-03-04 15:53:18 +01006017{
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006018 struct appctx *appctx = __objt_appctx(si->end);
Willy Tarreau74808cb2009-03-04 15:53:18 +01006019 extern const char *monthname[12];
Willy Tarreau74808cb2009-03-04 15:53:18 +01006020
Willy Tarreau2bb4a962014-11-28 11:11:05 +01006021 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
Willy Tarreau61b34732009-10-03 23:49:35 +02006022 return 1;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006023
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006024 chunk_reset(&trash);
Willy Tarreau74808cb2009-03-04 15:53:18 +01006025
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006026 if (!appctx->ctx.errors.px) {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006027 /* the function had not been called yet, let's prepare the
6028 * buffer for a response.
6029 */
Willy Tarreau10479e42010-12-12 14:00:34 +01006030 struct tm tm;
6031
6032 get_localtime(date.tv_sec, &tm);
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006033 chunk_appendf(&trash, "Total events captured on [%02d/%s/%04d:%02d:%02d:%02d.%03d] : %u\n",
Willy Tarreau10479e42010-12-12 14:00:34 +01006034 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
6035 tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(date.tv_usec/1000),
6036 error_snapshot_id);
6037
Willy Tarreau2bb4a962014-11-28 11:11:05 +01006038 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreau10479e42010-12-12 14:00:34 +01006039 /* Socket buffer full. Let's try again later from the same point */
Willy Tarreaufe127932015-04-21 19:23:39 +02006040 si_applet_cant_put(si);
Willy Tarreau10479e42010-12-12 14:00:34 +01006041 return 0;
6042 }
6043
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006044 appctx->ctx.errors.px = proxy;
6045 appctx->ctx.errors.buf = 0;
6046 appctx->ctx.errors.bol = 0;
6047 appctx->ctx.errors.ptr = -1;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006048 }
6049
6050 /* we have two inner loops here, one for the proxy, the other one for
6051 * the buffer.
6052 */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006053 while (appctx->ctx.errors.px) {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006054 struct error_snapshot *es;
6055
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006056 if (appctx->ctx.errors.buf == 0)
6057 es = &appctx->ctx.errors.px->invalid_req;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006058 else
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006059 es = &appctx->ctx.errors.px->invalid_rep;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006060
6061 if (!es->when.tv_sec)
6062 goto next;
6063
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006064 if (appctx->ctx.errors.iid >= 0 &&
6065 appctx->ctx.errors.px->uuid != appctx->ctx.errors.iid &&
6066 es->oe->uuid != appctx->ctx.errors.iid)
Willy Tarreau74808cb2009-03-04 15:53:18 +01006067 goto next;
6068
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006069 if (appctx->ctx.errors.ptr < 0) {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006070 /* just print headers now */
6071
6072 char pn[INET6_ADDRSTRLEN];
6073 struct tm tm;
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02006074 int port;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006075
6076 get_localtime(es->when.tv_sec, &tm);
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006077 chunk_appendf(&trash, " \n[%02d/%s/%04d:%02d:%02d:%02d.%03d]",
Willy Tarreau74808cb2009-03-04 15:53:18 +01006078 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreau1772ece2009-04-03 14:49:12 +02006079 tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(es->when.tv_usec/1000));
Willy Tarreau74808cb2009-03-04 15:53:18 +01006080
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02006081 switch (addr_to_str(&es->src, pn, sizeof(pn))) {
6082 case AF_INET:
6083 case AF_INET6:
6084 port = get_host_port(&es->src);
6085 break;
6086 default:
6087 port = 0;
6088 }
6089
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006090 switch (appctx->ctx.errors.buf) {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006091 case 0:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006092 chunk_appendf(&trash,
Willy Tarreau74808cb2009-03-04 15:53:18 +01006093 " frontend %s (#%d): invalid request\n"
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02006094 " backend %s (#%d)",
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006095 appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid,
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02006096 (es->oe->cap & PR_CAP_BE) ? es->oe->id : "<NONE>",
6097 (es->oe->cap & PR_CAP_BE) ? es->oe->uuid : -1);
Willy Tarreau74808cb2009-03-04 15:53:18 +01006098 break;
6099 case 1:
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006100 chunk_appendf(&trash,
Olivier Doucet08afdcb2014-09-08 11:23:00 +02006101 " backend %s (#%d): invalid response\n"
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02006102 " frontend %s (#%d)",
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006103 appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid,
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02006104 es->oe->id, es->oe->uuid);
Willy Tarreau74808cb2009-03-04 15:53:18 +01006105 break;
6106 }
6107
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006108 chunk_appendf(&trash,
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02006109 ", server %s (#%d), event #%u\n"
6110 " src %s:%d, session #%d, session flags 0x%08x\n"
6111 " HTTP msg state %d, msg flags 0x%08x, tx flags 0x%08x\n"
6112 " HTTP chunk len %lld bytes, HTTP body len %lld bytes\n"
6113 " buffer flags 0x%08x, out %d bytes, total %lld bytes\n"
6114 " pending %d bytes, wrapping at %d, error at position %d:\n \n",
6115 es->srv ? es->srv->id : "<NONE>", es->srv ? es->srv->puid : -1,
6116 es->ev_id,
6117 pn, port, es->sid, es->s_flags,
6118 es->state, es->m_flags, es->t_flags,
6119 es->m_clen, es->m_blen,
6120 es->b_flags, es->b_out, es->b_tot,
6121 es->len, es->b_wrap, es->pos);
6122
Willy Tarreau2bb4a962014-11-28 11:11:05 +01006123 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006124 /* Socket buffer full. Let's try again later from the same point */
Willy Tarreaufe127932015-04-21 19:23:39 +02006125 si_applet_cant_put(si);
Willy Tarreau61b34732009-10-03 23:49:35 +02006126 return 0;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006127 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006128 appctx->ctx.errors.ptr = 0;
6129 appctx->ctx.errors.sid = es->sid;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006130 }
6131
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006132 if (appctx->ctx.errors.sid != es->sid) {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006133 /* the snapshot changed while we were dumping it */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006134 chunk_appendf(&trash,
Willy Tarreau74808cb2009-03-04 15:53:18 +01006135 " WARNING! update detected on this snapshot, dump interrupted. Please re-check!\n");
Willy Tarreaubc18da12015-03-13 14:00:47 +01006136 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreaufe127932015-04-21 19:23:39 +02006137 si_applet_cant_put(si);
Willy Tarreau61b34732009-10-03 23:49:35 +02006138 return 0;
Willy Tarreaubc18da12015-03-13 14:00:47 +01006139 }
Willy Tarreau74808cb2009-03-04 15:53:18 +01006140 goto next;
6141 }
6142
6143 /* OK, ptr >= 0, so we have to dump the current line */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006144 while (appctx->ctx.errors.ptr < es->len && appctx->ctx.errors.ptr < sizeof(es->buf)) {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006145 int newptr;
6146 int newline;
6147
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006148 newline = appctx->ctx.errors.bol;
6149 newptr = dump_text_line(&trash, es->buf, sizeof(es->buf), es->len, &newline, appctx->ctx.errors.ptr);
6150 if (newptr == appctx->ctx.errors.ptr)
Willy Tarreau61b34732009-10-03 23:49:35 +02006151 return 0;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006152
Willy Tarreau2bb4a962014-11-28 11:11:05 +01006153 if (bi_putchk(si_ic(si), &trash) == -1) {
Willy Tarreau74808cb2009-03-04 15:53:18 +01006154 /* Socket buffer full. Let's try again later from the same point */
Willy Tarreaufe127932015-04-21 19:23:39 +02006155 si_applet_cant_put(si);
Willy Tarreau61b34732009-10-03 23:49:35 +02006156 return 0;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006157 }
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006158 appctx->ctx.errors.ptr = newptr;
6159 appctx->ctx.errors.bol = newline;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006160 };
6161 next:
Willy Tarreau7b4b4992013-12-01 09:15:12 +01006162 appctx->ctx.errors.bol = 0;
6163 appctx->ctx.errors.ptr = -1;
6164 appctx->ctx.errors.buf++;
6165 if (appctx->ctx.errors.buf > 1) {
6166 appctx->ctx.errors.buf = 0;
6167 appctx->ctx.errors.px = appctx->ctx.errors.px->next;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006168 }
6169 }
6170
6171 /* dump complete */
Willy Tarreau61b34732009-10-03 23:49:35 +02006172 return 1;
Willy Tarreau74808cb2009-03-04 15:53:18 +01006173}
6174
Willy Tarreaud5781202012-09-22 19:32:35 +02006175/* parse the "level" argument on the bind lines */
6176static int bind_parse_level(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
6177{
6178 if (!*args[cur_arg + 1]) {
6179 memprintf(err, "'%s' : missing level", args[cur_arg]);
6180 return ERR_ALERT | ERR_FATAL;
6181 }
6182
6183 if (!strcmp(args[cur_arg+1], "user"))
6184 conf->level = ACCESS_LVL_USER;
6185 else if (!strcmp(args[cur_arg+1], "operator"))
6186 conf->level = ACCESS_LVL_OPER;
6187 else if (!strcmp(args[cur_arg+1], "admin"))
6188 conf->level = ACCESS_LVL_ADMIN;
6189 else {
6190 memprintf(err, "'%s' only supports 'user', 'operator', and 'admin' (got '%s')",
6191 args[cur_arg], args[cur_arg+1]);
6192 return ERR_ALERT | ERR_FATAL;
6193 }
6194
6195 return 0;
6196}
6197
Willy Tarreau30576452015-04-13 13:50:30 +02006198struct applet http_stats_applet = {
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006199 .obj_type = OBJ_TYPE_APPLET,
Willy Tarreaub24281b2011-02-13 13:16:36 +01006200 .name = "<STATS>", /* used for logging */
6201 .fct = http_stats_io_handler,
Aman Gupta9a13e842012-04-02 18:57:53 -07006202 .release = NULL,
Willy Tarreaub24281b2011-02-13 13:16:36 +01006203};
6204
Willy Tarreau30576452015-04-13 13:50:30 +02006205static struct applet cli_applet = {
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006206 .obj_type = OBJ_TYPE_APPLET,
Willy Tarreaub24281b2011-02-13 13:16:36 +01006207 .name = "<CLI>", /* used for logging */
6208 .fct = cli_io_handler,
Willy Tarreau5f9a8772012-11-26 02:22:40 +01006209 .release = cli_release_handler,
Willy Tarreaub24281b2011-02-13 13:16:36 +01006210};
Willy Tarreau3dfe6cd2008-12-07 22:29:48 +01006211
Willy Tarreaudc13c112013-06-21 23:16:39 +02006212static struct cfg_kw_list cfg_kws = {ILH, {
Willy Tarreau10522fd2008-07-09 20:12:41 +02006213 { CFG_GLOBAL, "stats", stats_parse_global },
6214 { 0, NULL, NULL },
6215}};
6216
Willy Tarreaud5781202012-09-22 19:32:35 +02006217static struct bind_kw_list bind_kws = { "STAT", { }, {
6218 { "level", bind_parse_level, 1 }, /* set the unix socket admin level */
6219 { NULL, NULL, 0 },
6220}};
6221
Willy Tarreau10522fd2008-07-09 20:12:41 +02006222__attribute__((constructor))
6223static void __dumpstats_module_init(void)
6224{
6225 cfg_register_keywords(&cfg_kws);
Willy Tarreaud5781202012-09-22 19:32:35 +02006226 bind_register_keywords(&bind_kws);
Willy Tarreau10522fd2008-07-09 20:12:41 +02006227}
6228
Willy Tarreau91861262007-10-17 17:06:05 +02006229/*
6230 * Local variables:
6231 * c-indent-level: 8
6232 * c-basic-offset: 8
6233 * End:
6234 */