[MINOR] More flexible clearing of stick table

* Allow clearing of all entries of a table
* Allow clearing of all entries of a table
  that match a data filter
This commit is contained in:
Simon Horman 2011-06-15 15:18:49 +09:00 committed by Willy Tarreau
parent d5b9fd9591
commit c88b887d8d
3 changed files with 63 additions and 26 deletions

View File

@ -9309,15 +9309,34 @@ clear counters all
server. This has the same effect as restarting. This command is restricted
and can only be issued on sockets configured for level "admin".
clear table <table> key <key>
Remove entry <key> from the stick-table <table>. The key must be of the same
type as the table, which currently is limited to IPv4. This is typically used
un unblock some users complaining they have been abusively denied access to a
service, but this can also be used to clear some stickiness entries matching
a server that is going to be replaced (see "show table" below for details).
Note that sometimes, removal of a key will be refused because it is currently
tracked by a session. Retrying a few seconds later after the session ends is
usuall enough.
clear table <table> [ data.<type> <operator> <value> ] | [ key <key> ]
Remove entries from the stick-table <table>.
This is typically used to unblock some users complaining they have been
abusively denied access to a service, but this can also be used to clear some
stickiness entries matching a server that is going to be replaced (see "show
table" below for details). Note that sometimes, removal of an entry will be
refused because it is currently tracked by a session. Retrying a few seconds
later after the session ends is usual enough.
In the case where no options arguments are given all entries will be removed.
When the "data." form is used entries matching a filter applied using the
stored data (see "stick-table" in section 4.2) are removed. A stored data
type must be specified in <type>, and this data type must be stored in the
table otherwise an error is reported. The data is compared according to
<operator> with the 64-bit integer <value>. Operators are the same as with
the ACLs :
- eq : match entries whose data is equal to this value
- ne : match entries whose data is not equal to this value
- le : match entries whose data is less than or equal to this value
- ge : match entries whose data is greater than or equal to this value
- lt : match entries whose data is less than this value
- gt : match entries whose data is greater than this value
When the key form is used the entry <key> is removed. The key must be of the
same type as the table, which currently is limited to IPv4.
Example :
$ echo "show table http_proxy" | socat stdio /tmp/sock1
@ -9333,6 +9352,9 @@ clear table <table> key <key>
>>> # table: http_proxy, type: ip, size:204800, used:1
>>> 0x80e6a80: key=127.0.0.2 use=0 exp=3594740 gpc0=1 conn_rate(30000)=10 \
bytes_out_rate(60000)=191
$ echo "clear table http_proxy data.gpc0 eq 1" | socat stdio /tmp/sock1
$ echo "show table http_proxy" | socat stdio /tmp/sock1
>>> # table: http_proxy, type: ip, size:204800, used:1
disable server <backend>/<server>
Mark the server DOWN for maintenance. In this mode, no more checks will be
@ -9538,10 +9560,9 @@ show table <name> [ data.<type> <operator> <value> ] | [ key <key> ]
- lt : match entries whose data is less than this value
- gt : match entries whose data is greater than this value
When the key form is used the filter applies to the key of
the stick table entry (see "stick-table" in section 4.2).
The stick table must be of type ip otherwise an error will
be reported.
When the key form is used the entry <key> is shown. The key must be of the
same type as the table, which currently is limited to IPv4.
Example :
$ echo "show table http_proxy" | socat stdio /tmp/sock1

View File

@ -53,6 +53,7 @@
#define STAT_CLI_O_SESS 6 /* dump sessions */
#define STAT_CLI_O_ERR 7 /* dump errors */
#define STAT_CLI_O_TAB 8 /* dump tables */
#define STAT_CLI_O_CLR 9 /* clear tables */
/* status codes (strictly 4 chars) used in the URL to display a message */
#define STAT_STATUS_UNKN "UNKN" /* an unknown error occured, shouldn't happen */

View File

@ -59,7 +59,7 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si);
static int stats_dump_full_sess_to_buffer(struct stream_interface *si);
static int stats_dump_sess_to_buffer(struct stream_interface *si);
static int stats_dump_errors_to_buffer(struct stream_interface *si);
static int stats_dump_table_to_buffer(struct stream_interface *si);
static int stats_table_request(struct stream_interface *si, bool show);
static int stats_dump_proxy(struct stream_interface *si, struct proxy *px, struct uri_auth *uri);
static int stats_dump_http(struct stream_interface *si, struct uri_auth *uri);
@ -599,7 +599,10 @@ static void stats_sock_table_request(struct stream_interface *si, char **args, b
si->applet.state = STAT_ST_INIT;
si->applet.ctx.table.proxy = NULL;
si->applet.ctx.table.entry = NULL;
si->applet.st0 = STAT_CLI_O_TAB; // stats_dump_table_to_buffer
if (show)
si->applet.st0 = STAT_CLI_O_TAB;
else
si->applet.st0 = STAT_CLI_O_CLR;
if (*args[2]) {
si->applet.ctx.table.target = find_stktable(args[2]);
@ -617,9 +620,9 @@ static void stats_sock_table_request(struct stream_interface *si, char **args, b
if (strcmp(args[3], "key") == 0)
stats_sock_table_key_request(si, args, show);
else if (show && strncmp(args[3], "data.", 5) == 0)
else if (strncmp(args[3], "data.", 5) == 0)
stats_sock_table_data_request(si, args);
else if (!show || *args[3])
else if (*args[3])
goto err_args;
return;
@ -628,7 +631,7 @@ err_args:
if (show)
si->applet.ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
else
si->applet.ctx.cli.msg = "Required arguments: <table> key <key>\n";
si->applet.ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
si->applet.st0 = STAT_CLI_PRINT;
}
@ -1181,7 +1184,11 @@ static void cli_io_handler(struct stream_interface *si)
si->applet.st0 = STAT_CLI_PROMPT;
break;
case STAT_CLI_O_TAB:
if (stats_dump_table_to_buffer(si))
if (stats_table_request(si, true))
si->applet.st0 = STAT_CLI_PROMPT;
break;
case STAT_CLI_O_CLR:
if (stats_table_request(si, false))
si->applet.st0 = STAT_CLI_PROMPT;
break;
default: /* abnormal state */
@ -3306,12 +3313,13 @@ static int stats_dump_sess_to_buffer(struct stream_interface *si)
* properly set. It returns 0 if the output buffer is full and it needs
* to be called again, otherwise non-zero.
*/
static int stats_dump_table_to_buffer(struct stream_interface *si)
static int stats_table_request(struct stream_interface *si, bool show)
{
struct session *s = si->applet.private;
struct chunk msg;
struct ebmb_node *eb;
int dt;
bool skip_entry;
/*
* We have 3 possible states in si->applet.state :
@ -3356,8 +3364,8 @@ static int stats_dump_table_to_buffer(struct stream_interface *si)
}
if (si->applet.ctx.table.proxy->table.size) {
if (!stats_dump_table_head_to_buffer(&msg, si, si->applet.ctx.table.proxy,
si->applet.ctx.table.target))
if (show && !stats_dump_table_head_to_buffer(&msg, si, si->applet.ctx.table.proxy,
si->applet.ctx.table.target))
return 0;
if (si->applet.ctx.table.target &&
@ -3376,6 +3384,8 @@ static int stats_dump_table_to_buffer(struct stream_interface *si)
break;
case STAT_ST_LIST:
skip_entry = false;
if (si->applet.ctx.table.data_type >= 0) {
/* we're filtering on some data contents */
void *ptr;
@ -3416,14 +3426,14 @@ static int stats_dump_table_to_buffer(struct stream_interface *si)
(si->applet.ctx.table.data_op == STD_OP_EQ ||
si->applet.ctx.table.data_op == STD_OP_LT ||
si->applet.ctx.table.data_op == STD_OP_LE)))
goto skip_entry;
skip_entry = true;
}
if (!stats_dump_table_entry_to_buffer(&msg, si, si->applet.ctx.table.proxy,
if (show && !skip_entry &&
!stats_dump_table_entry_to_buffer(&msg, si, si->applet.ctx.table.proxy,
si->applet.ctx.table.entry))
return 0;
skip_entry:
si->applet.ctx.table.entry->ref_cnt--;
eb = ebmb_next(&si->applet.ctx.table.entry->key);
@ -3435,7 +3445,12 @@ static int stats_dump_table_to_buffer(struct stream_interface *si)
break;
}
stksess_kill_if_expired(&si->applet.ctx.table.proxy->table, si->applet.ctx.table.entry);
if (show)
stksess_kill_if_expired(&si->applet.ctx.table.proxy->table, si->applet.ctx.table.entry);
else if (!skip_entry && !si->applet.ctx.table.entry->ref_cnt)
stksess_kill(&si->applet.ctx.table.proxy->table, si->applet.ctx.table.entry);
si->applet.ctx.table.proxy = si->applet.ctx.table.proxy->next;
si->applet.state = STAT_ST_INFO;
break;