]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] More flexible clearing of stick table
authorSimon Horman <horms@verge.net.au>
Wed, 15 Jun 2011 06:18:49 +0000 (15:18 +0900)
committerWilly Tarreau <w@1wt.eu>
Fri, 17 Jun 2011 09:39:29 +0000 (11:39 +0200)
* Allow clearing of all entries of a table
* Allow clearing of all entries of a table
  that match a data filter

doc/configuration.txt
include/proto/dumpstats.h
src/dumpstats.c

index a21c43a9e10e81f946cd3dba86c4ccfd4f7f6a3f..9bf9900381bda49b66a2c6d5afe5af34f51c0e6a 100644 (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
index 850819a2af2bf817a6ca30952ae7d63313d4dd14..eb44a363299b168ddc5bb2ee212f563bd3a299fa 100644 (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 */
index 6adcee281bac18156ca619e57d0503f872635e7c..8cd82ad8c40b19bb18e9011b4d4e8c1abc296f99 100644 (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;