]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: map/acl: add the possibility to specify the version in "clear map/acl"
authorWilly Tarreau <w@1wt.eu>
Fri, 30 Apr 2021 11:31:43 +0000 (13:31 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 30 Apr 2021 13:36:31 +0000 (15:36 +0200)
This will ease maintenance of versionned maps by allowing to clear old or
failed updates instead of the current version. Nothing was done to allow
clearing everyhing, though if there was a need for this, implementing "@all"
or something equivalent wouldn't require more than 3 lines of code.

doc/management.txt
src/map.c

index c15e71af99fb1f1e41cc4b8fc6c3ee0cf68302e0..6ccd468f449f8e61c85945dd5c0cad40d1a88fac 100644 (file)
@@ -1495,15 +1495,19 @@ 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 acl <acl>
+clear acl [@<ver>] <acl>
   Remove all entries from the acl <acl>. <acl> is the #<id> or the <file>
   returned by "show acl". Note that if the reference <acl> is a file and is
-  shared with a map, this map will be also cleared.
+  shared with a map, this map will be also cleared. By default only the current
+  version of the ACL is cleared (the one being matched against). However it is
+  possible to specify another version using '@' followed by this version.
 
-clear map <map>
+clear map [@<ver>] <map>
   Remove all entries from the map <map>. <map> is the #<id> or the <file>
   returned by "show map". Note that if the reference <map> is a file and is
-  shared with a acl, this acl will be also cleared.
+  shared with a acl, this acl will be also cleared. By default only the current
+  version of the map is cleared (the one being matched against). However it is
+  possible to specify another version using '@' followed by this version.
 
 clear table <table> [ data.<type> <operator> <value> ] | [ key <key> ]
   Remove entries from the stick-table <table>.
index 080fee85d146754e20cb63a861b0a3c9d0094b75..42b3bdcaad96fd956462bf3b2135ec5386d0a853 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -935,15 +935,17 @@ static int cli_parse_del_map(char **args, char *payload, struct appctx *appctx,
        return 1;
 }
 
-
-/* continue to clear a map which was started in the parser */
+/* continue to clear a map which was started in the parser. The range of
+ * generations this applies to is taken from appctx->ctx.cli.i0 for the oldest
+ * and appctx->ctx.cli.i1 for the latest.
+ */
 static int cli_io_handler_clear_map(struct appctx *appctx)
 {
        struct stream_interface *si = appctx->owner;
        int finished;
 
        HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-       finished = pat_ref_prune(appctx->ctx.map.ref);
+       finished = pat_ref_purge_range(appctx->ctx.map.ref, appctx->ctx.cli.i0, appctx->ctx.cli.i1, 100);
        HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
 
        if (!finished) {
@@ -954,15 +956,30 @@ static int cli_io_handler_clear_map(struct appctx *appctx)
        return 1;
 }
 
+/* note: sets appctx->ctx.cli.i0 and appctx->ctx.cli.i1 to the oldest and
+ * latest generations to clear, respectively, and will call the clear_map
+ * handler.
+ */
 static int cli_parse_clear_map(char **args, char *payload, struct appctx *appctx, void *private)
 {
        if (strcmp(args[1], "map") == 0 || strcmp(args[1], "acl") == 0) {
+               const char *gen = NULL;
+
                /* Set ACL or MAP flags. */
                if (args[1][0] == 'm')
                        appctx->ctx.map.display_flags = PAT_REF_MAP;
                else
                        appctx->ctx.map.display_flags = PAT_REF_ACL;
 
+               /* For both "map" and "acl" we may have an optional generation
+                * number specified using a "@" character before the pattern
+                * file name.
+                */
+               if (*args[2] == '@') {
+                       gen = args[2] + 1;
+                       args++;
+               }
+
                /* no parameter */
                if (!*args[2]) {
                        if (appctx->ctx.map.display_flags == PAT_REF_MAP)
@@ -981,6 +998,12 @@ static int cli_parse_clear_map(char **args, char *payload, struct appctx *appctx
                                return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
                }
 
+               /* set the desired generation id in cli.i0/i1 */
+               if (gen)
+                       appctx->ctx.cli.i1 = appctx->ctx.cli.i0 = str2uic(gen);
+               else
+                       appctx->ctx.cli.i1 = appctx->ctx.cli.i0 = appctx->ctx.map.ref->curr_gen;
+
                /* delegate the clearing to the I/O handler which can yield */
                return 0;
        }
@@ -991,12 +1014,12 @@ static int cli_parse_clear_map(char **args, char *payload, struct appctx *appctx
 
 static struct cli_kw_list cli_kws = {{ },{
        { { "add",   "acl", NULL }, "add acl        : add acl entry", cli_parse_add_map, NULL },
-       { { "clear", "acl", NULL }, "clear acl <id> : clear the content of this acl", cli_parse_clear_map, cli_io_handler_clear_map, NULL },
+       { { "clear", "acl", NULL }, "clear acl [@ver] <id> : clear the content of this acl", cli_parse_clear_map, cli_io_handler_clear_map, NULL },
        { { "del",   "acl", NULL }, "del acl        : delete acl entry", cli_parse_del_map, NULL },
        { { "get",   "acl", NULL }, "get acl        : report the patterns matching a sample for an ACL", cli_parse_get_map, cli_io_handler_map_lookup, cli_release_mlook },
        { { "show",  "acl", NULL }, "show acl [@ver] [id] : report available acls or dump an acl's contents", cli_parse_show_map, NULL },
        { { "add",   "map", NULL }, "add map        : add map entry", cli_parse_add_map, NULL },
-       { { "clear", "map", NULL }, "clear map <id> : clear the content of this map", cli_parse_clear_map, cli_io_handler_clear_map, NULL },
+       { { "clear", "map", NULL }, "clear map [@ver] <id> : clear the content of this map", cli_parse_clear_map, cli_io_handler_clear_map, NULL },
        { { "del",   "map", NULL }, "del map        : delete map entry", cli_parse_del_map, NULL },
        { { "get",   "map", NULL }, "get map        : report the keys and values matching a sample for a map", cli_parse_get_map, cli_io_handler_map_lookup, cli_release_mlook },
        { { "set",   "map", NULL }, "set map        : modify map entry", cli_parse_set_map, NULL },