73
73
"Permission denied\n"
76
/* allocate a new stats frontend named <name>, and return it
77
* (or NULL in case of lack of memory).
79
static struct proxy *alloc_stats_fe(const char *name)
83
fe = (struct proxy *)calloc(1, sizeof(struct proxy));
87
LIST_INIT(&fe->pendconns);
89
LIST_INIT(&fe->block_cond);
90
LIST_INIT(&fe->redirect_rules);
91
LIST_INIT(&fe->mon_fail_cond);
92
LIST_INIT(&fe->switching_rules);
93
LIST_INIT(&fe->tcp_req.inspect_rules);
95
/* Timeouts are defined as -1, so we cannot use the zeroed area
98
proxy_reset_timeouts(fe);
100
fe->last_change = now.tv_sec;
101
fe->id = strdup("GLOBAL");
76
106
/* This function parses a "stats" statement in the "global" section. It returns
77
107
* -1 if there is any error, otherwise zero. If it returns -1, it may write an
78
108
* error message into ther <err> buffer, for at most <errlen> bytes, trailing
100
su.sun_family = AF_UNIX;
101
strncpy(su.sun_path, args[1], sizeof(su.sun_path));
102
su.sun_path[sizeof(su.sun_path) - 1] = 0;
103
memcpy(&global.stats_sock.addr, &su, sizeof(su)); // guaranteed to fit
130
su = str2sun(args[1]);
132
snprintf(err, errlen, "'stats socket' path would require truncation");
135
memcpy(&global.stats_sock.addr, su, sizeof(struct sockaddr_un)); // guaranteed to fit
105
137
if (!global.stats_fe) {
106
if ((global.stats_fe = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
138
if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) {
107
139
snprintf(err, errlen, "out of memory");
111
LIST_INIT(&global.stats_fe->pendconns);
112
LIST_INIT(&global.stats_fe->acl);
113
LIST_INIT(&global.stats_fe->block_cond);
114
LIST_INIT(&global.stats_fe->redirect_rules);
115
LIST_INIT(&global.stats_fe->mon_fail_cond);
116
LIST_INIT(&global.stats_fe->switching_rules);
117
LIST_INIT(&global.stats_fe->tcp_req.inspect_rules);
119
/* Timeouts are defined as -1, so we cannot use the zeroed area
120
* as a default value.
122
proxy_reset_timeouts(global.stats_fe);
124
global.stats_fe->last_change = now.tv_sec;
125
global.stats_fe->id = strdup("GLOBAL");
126
global.stats_fe->cap = PR_CAP_FE;
142
global.stats_fe->timeout.client = MS_TO_TICKS(10000); /* default timeout of 10 seconds */
129
145
global.stats_sock.state = LI_INIT;
134
150
global.stats_sock.nice = -64; /* we want to boost priority for local stats */
135
151
global.stats_sock.private = global.stats_fe; /* must point to the frontend */
136
152
global.stats_sock.perm.ux.level = ACCESS_LVL_OPER; /* default access level */
138
global.stats_fe->timeout.client = MS_TO_TICKS(10000); /* default timeout of 10 seconds */
139
153
global.stats_sock.timeout = &global.stats_fe->timeout.client;
141
155
global.stats_sock.next = global.stats_fe->listen;
212
226
snprintf(err, errlen, "a positive value is expected for 'stats timeout' in 'global section'");
229
if (!global.stats_fe) {
230
if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) {
231
snprintf(err, errlen, "out of memory");
215
235
global.stats_fe->timeout.client = MS_TO_TICKS(timeout);
217
237
else if (!strcmp(args[0], "maxconn")) {
483
if (px->state == PR_STSTOPPED) {
484
s->data_ctx.cli.msg = "Proxy is disabled.\n";
485
si->st0 = STAT_CLI_PRINT;
463
489
/* if the weight is terminated with '%', it is set relative to
464
490
* the initial weight, otherwise it is absolute.
599
if (px->state == PR_STSTOPPED) {
600
s->data_ctx.cli.msg = "Proxy is disabled.\n";
601
si->st0 = STAT_CLI_PRINT;
573
605
if (sv->state & SRV_MAINTAIN) {
574
606
/* The server is really in maintenance, we can change the server state */
575
607
if (sv->tracked) {
579
611
if (sv->tracked->state & SRV_RUNNING) {
580
612
set_server_up(sv);
613
sv->health = sv->rise; /* up, but will fall down at first failure */
582
615
sv->state &= ~SRV_MAINTAIN;
583
616
set_server_down(sv);
586
619
set_server_up(sv);
620
sv->health = sv->rise; /* up, but will fall down at first failure */
660
if (px->state == PR_STSTOPPED) {
661
s->data_ctx.cli.msg = "Proxy is disabled.\n";
662
si->st0 = STAT_CLI_PRINT;
626
666
if (! (sv->state & SRV_MAINTAIN)) {
627
667
/* Not already in maintenance, we can change the server state */
628
668
sv->state |= SRV_MAINTAIN;
997
/* We don't want to land on the posted stats page because a refresh will
998
* repost the data. We don't want this to happen on accident so we redirect
999
* the browse to the stats page with a GET.
1001
int stats_http_redir(struct session *s, struct buffer *rep, struct uri_auth *uri)
1005
chunk_init(&msg, trash, sizeof(trash));
1007
switch (s->data_state) {
1010
"HTTP/1.0 303 See Other\r\n"
1011
"Cache-Control: no-cache\r\n"
1012
"Content-Type: text/plain\r\n"
1013
"Connection: close\r\n"
1014
"Location: %s;st=%s",
1015
uri->uri_prefix, s->data_ctx.stats.st_code);
1016
chunk_printf(&msg, "\r\n\r\n");
1018
if (buffer_feed_chunk(rep, &msg) >= 0)
1021
s->txn.status = 303;
1023
if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
1024
s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
1025
if (!(s->flags & SN_FINST_MASK))
1026
s->flags |= SN_FINST_R;
1028
s->data_state = DATA_ST_FIN;
957
1035
/* This I/O handler runs as an applet embedded in a stream interface. It is
958
1036
* used to send HTTP stats over a TCP socket. The mechanism is very simple.
959
1037
* si->st0 becomes non-zero once the transfer is finished. The handler
976
if (stats_dump_http(s, res, s->be->uri_auth)) {
1054
if (s->txn.meth == HTTP_METH_POST) {
1055
if (stats_http_redir(s, res, s->be->uri_auth)) {
1060
if (stats_dump_http(s, res, s->be->uri_auth)) {
1353
if (s->data_ctx.stats.st_code) {
1354
if (strcmp(s->data_ctx.stats.st_code, STAT_STATUS_DONE) == 0) {
1356
"<p><div class=active3>"
1357
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
1358
"Action processed successfully."
1359
"</div>\n", uri->uri_prefix);
1361
else if (strcmp(s->data_ctx.stats.st_code, STAT_STATUS_NONE) == 0) {
1363
"<p><div class=active2>"
1364
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
1365
"Nothing has changed."
1366
"</div>\n", uri->uri_prefix);
1368
else if (strcmp(s->data_ctx.stats.st_code, STAT_STATUS_EXCD) == 0) {
1370
"<p><div class=active0>"
1371
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
1372
"<b>Action not processed : the buffer couldn't store all the data.<br>"
1373
"You should retry with less servers at a time.</b>"
1374
"</div>\n", uri->uri_prefix);
1376
else if (strcmp(s->data_ctx.stats.st_code, STAT_STATUS_DENY) == 0) {
1378
"<p><div class=active0>"
1379
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
1380
"<b>Action denied.</b>"
1381
"</div>\n", uri->uri_prefix);
1385
"<p><div class=active6>"
1386
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
1387
"Unexpected result."
1388
"</div>\n", uri->uri_prefix);
1390
chunk_printf(&msg,"<p>\n");
1268
1393
if (buffer_feed_chunk(rep, &msg) >= 0)
1366
1491
case DATA_ST_PX_TH:
1367
1492
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
1493
if (px->cap & PR_CAP_BE && px->srv && (s->data_ctx.stats.flags & STAT_ADMIN)) {
1494
/* A form to enable/disable this proxy servers */
1496
"<form action=\"%s\" method=\"post\">",
1368
1500
/* print a new table */
1369
1501
chunk_printf(&msg,
1370
1502
"<table class=\"tbl\" width=\"100%%\">\n"
1389
1521
"<table class=\"tbl\" width=\"100%%\">\n"
1390
"<tr class=\"titre\">"
1522
"<tr class=\"titre\">",
1523
(uri->flags & ST_SHLGNDS)?"<u>":"",
1524
px->id, px->id, px->id,
1525
(uri->flags & ST_SHLGNDS)?"</u>":"",
1526
px->desc ? "desc" : "empty", px->desc ? px->desc : "");
1528
if (px->cap & PR_CAP_BE && px->srv && (s->data_ctx.stats.flags & STAT_ADMIN)) {
1529
/* Column heading for Enable or Disable server */
1530
chunk_printf(&msg, "<th rowspan=2 width=1></th>");
1391
1534
"<th rowspan=2></th>"
1392
1535
"<th colspan=3>Queue</th>"
1393
1536
"<th colspan=3>Session rate</th><th colspan=5>Sessions</th>"
1404
1547
"<th>Status</th><th>LastChk</th><th>Wght</th><th>Act</th>"
1405
1548
"<th>Bck</th><th>Chk</th><th>Dwn</th><th>Dwntme</th>"
1406
1549
"<th>Thrtle</th>\n"
1408
(uri->flags & ST_SHLGNDS)?"<u>":"",
1409
px->id, px->id, px->id,
1410
(uri->flags & ST_SHLGNDS)?"</u>":"",
1411
px->desc ? "desc" : "empty", px->desc ? px->desc : "");
1413
1552
if (buffer_feed_chunk(rep, &msg) >= 0)
1424
1563
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
1425
1564
chunk_printf(&msg,
1426
1565
/* name, queue */
1427
"<tr class=\"frontend\"><td class=ac>"
1566
"<tr class=\"frontend\">");
1568
if (px->cap & PR_CAP_BE && px->srv && (s->data_ctx.stats.flags & STAT_ADMIN)) {
1569
/* Column sub-heading for Enable or Disable server */
1570
chunk_printf(&msg, "<td></td>");
1428
1575
"<a name=\"%s/Frontend\"></a>"
1429
"<a class=lfsb href=\"#%s/Frontend\">Frontend</a></td><td colspan=3></td>"
1576
"<a class=lfsb href=\"#%s/Frontend\">Frontend</a></td>"
1577
"<td colspan=3></td>"
1431
1579
px->id, px->id);
1438
1586
read_freq_ctr(&px->fe_req_per_sec),
1439
1587
U2H0(read_freq_ctr(&px->fe_sess_per_sec)),
1440
1588
px->counters.fe_rps_max,
1441
U2H2(px->counters.fe_sps_max),
1589
U2H1(px->counters.fe_sps_max),
1442
1590
LIM2A2(px->fe_sps_lim, "-"));
1444
1592
chunk_printf(&msg,
1586
1734
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
1587
chunk_printf(&msg, "<tr class=socket><td class=ac");
1735
chunk_printf(&msg, "<tr class=socket>");
1736
if (px->cap & PR_CAP_BE && px->srv && (s->data_ctx.stats.flags & STAT_ADMIN)) {
1737
/* Column sub-heading for Enable or Disable server */
1738
chunk_printf(&msg, "<td></td>");
1740
chunk_printf(&msg, "<td class=ac");
1589
1742
if (uri->flags&ST_SHLGNDS) {
1590
1743
char str[INET6_ADDRSTRLEN], *fmt = NULL;
1758
1911
if ((sv->state & SRV_MAINTAIN) || (svs->state & SRV_MAINTAIN)) {
1759
1912
chunk_printf(&msg,
1761
"<tr class=\"maintain\"><td class=ac"
1914
"<tr class=\"maintain\">"
1765
1918
chunk_printf(&msg,
1767
"<tr class=\"%s%d\"><td class=ac",
1920
"<tr class=\"%s%d\">",
1768
1921
(sv->state & SRV_BACKUP) ? "backup" : "active", sv_state);
1924
if (px->cap & PR_CAP_BE && px->srv && (s->data_ctx.stats.flags & STAT_ADMIN)) {
1926
"<td><input type=\"checkbox\" name=\"s\" value=\"%s\"></td>",
1930
chunk_printf(&msg, "<td class=ac");
1771
1932
if (uri->flags&ST_SHLGNDS) {
1772
1933
char str[INET6_ADDRSTRLEN];
2098
2259
if ((px->cap & PR_CAP_BE) &&
2099
2260
(!(s->data_ctx.stats.flags & STAT_BOUND) || (s->data_ctx.stats.type & (1 << STATS_TYPE_BE)))) {
2100
2261
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
2103
"<tr class=\"backend\"><td class=ac");
2262
chunk_printf(&msg, "<tr class=\"backend\">");
2263
if (px->cap & PR_CAP_BE && px->srv && (s->data_ctx.stats.flags & STAT_ADMIN)) {
2264
/* Column sub-heading for Enable or Disable server */
2265
chunk_printf(&msg, "<td></td>");
2267
chunk_printf(&msg, "<td class=ac");
2105
2269
if (uri->flags&ST_SHLGNDS) {
2106
2270
/* balancing */
2287
2452
case DATA_ST_PX_END:
2288
2453
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
2289
chunk_printf(&msg, "</table><p>\n");
2454
chunk_printf(&msg, "</table>");
2456
if (px->cap & PR_CAP_BE && px->srv && (s->data_ctx.stats.flags & STAT_ADMIN)) {
2457
/* close the form used to enable/disable this proxy servers */
2459
"Choose the action to perform on the checked servers : "
2460
"<select name=action>"
2461
"<option value=\"\"></option>"
2462
"<option value=\"disable\">Disable</option>"
2463
"<option value=\"enable\">Enable</option>"
2465
"<input type=\"hidden\" name=\"b\" value=\"%s\">"
2466
" <input type=\"submit\" value=\"Apply\">"
2471
chunk_printf(&msg, "<p>\n");
2291
2473
if (buffer_feed_chunk(rep, &msg) >= 0)
2807
2989
/* the function had not been called yet, let's prepare the
2808
2990
* buffer for a response.
2994
get_localtime(date.tv_sec, &tm);
2995
chunk_printf(&msg, "Total events captured on [%02d/%s/%04d:%02d:%02d:%02d.%03d] : %u\n",
2996
tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
2997
tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(date.tv_usec/1000),
3000
if (buffer_feed_chunk(rep, &msg) >= 0) {
3001
/* Socket buffer full. Let's try again later from the same point */
2810
3005
s->data_ctx.errors.px = proxy;
2811
3006
s->data_ctx.errors.buf = 0;
2812
3007
s->data_ctx.errors.bol = 0;
2858
3053
chunk_printf(&msg,
2859
3054
" frontend %s (#%d): invalid request\n"
2860
3055
" src %s, session #%d, backend %s (#%d), server %s (#%d)\n"
3056
" HTTP internal state %d, buffer flags 0x%08x, event #%u\n"
2861
3057
" request length %d bytes, error at position %d:\n \n",
2862
3058
s->data_ctx.errors.px->id, s->data_ctx.errors.px->uuid,
2863
3059
pn, es->sid, (es->oe->cap & PR_CAP_BE) ? es->oe->id : "<NONE>",
2864
3060
(es->oe->cap & PR_CAP_BE) ? es->oe->uuid : -1,
2865
3061
es->srv ? es->srv->id : "<NONE>",
2866
3062
es->srv ? es->srv->puid : -1,
3063
es->state, es->flags, es->ev_id,
2867
3064
es->len, es->pos);
2870
3067
chunk_printf(&msg,
2871
3068
" backend %s (#%d) : invalid response\n"
2872
3069
" src %s, session #%d, frontend %s (#%d), server %s (#%d)\n"
3070
" HTTP internal state %d, buffer flags 0x%08x, event #%u\n"
2873
3071
" response length %d bytes, error at position %d:\n \n",
2874
3072
s->data_ctx.errors.px->id, s->data_ctx.errors.px->uuid,
2875
3073
pn, es->sid, es->oe->id, es->oe->uuid,
2876
3074
es->srv ? es->srv->id : "<NONE>",
2877
3075
es->srv ? es->srv->puid : -1,
3076
es->state, es->flags, es->ev_id,
2878
3077
es->len, es->pos);