[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
diff --git a/doc/configuration.txt b/doc/configuration.txt
index a21c43a..9bf9900 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -9309,15 +9309,34 @@
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 @@
>>> # 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 @@
- 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
diff --git a/include/proto/dumpstats.h b/include/proto/dumpstats.h
index 850819a..eb44a36 100644
--- a/include/proto/dumpstats.h
+++ b/include/proto/dumpstats.h
@@ -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 */
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 6adcee2..8cd82ad 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -59,7 +59,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
}
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 @@
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 @@
(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 @@
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;