]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: map/acl: add the "prepare map/acl" CLI command
authorWilly Tarreau <w@1wt.eu>
Fri, 30 Apr 2021 12:57:03 +0000 (14:57 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 30 Apr 2021 13:36:31 +0000 (15:36 +0200)
This command allocates a new version for the map/acl, that will be usable
later to prepare the addition of new values to atomically replace existing
ones. Technically speaking the operation consists in atomically incrementing
the next version. There's no "undo" operation here, if a version is not
committed, it will automatically be trashed when committing a newer version.

doc/management.txt
src/map.c

index 6ccd468f449f8e61c85945dd5c0cad40d1a88fac..96660e7f1dbc3f770ded9d254cbd93ec51a1ac20 100644 (file)
@@ -1806,6 +1806,30 @@ new ssl cert <filename>
   added to a directory or a crt-list. This command should be used in
   combination with "set ssl cert" and "add ssl crt-list".
 
+prepare acl <acl>
+  Allocate a new version number in ACL <acl> for atomic replacement. <acl> is
+  the #<id> or the <file> returned by "show acl". The new version number is
+  shown in response after "New version created:". This number will then be
+  usable to prepare additions of new entries into the ACL which will then
+  atomically replace the current ones once committed. It is reported as
+  "next_ver" in "show acl". There is no impact of allocating new versions, as
+  unused versions will automatically be removed once a more recent version is
+  committed. Version numbers are unsigned 32-bit values which wrap at the end,
+  so care must be taken when comparing them in an external program. This
+  command cannot be used if the reference <acl> is a file also used as a map.
+  In this case, the "prepare map" command must be used instead.
+
+prepare map <map>
+  Allocate a new version number in map <map> for atomic replacement. <map> is
+  the #<id> or the <file> returned by "show map". The new version number is
+  shown in response after "New version created:". This number will then be
+  usable to prepare additions of new entries into the map which will then
+  atomically replace the current ones once committed. It is reported as
+  "next_ver" in "show map". There is no impact of allocating new versions, as
+  unused versions will automatically be removed once a more recent version is
+  committed. Version numbers are unsigned 32-bit values which wrap at the end,
+  so care must be taken when comparing them in an external program.
+
 prompt
   Toggle the prompt at the beginning of the line and enter or leave interactive
   mode. In interactive mode, the connection is not closed after a command
index 42b3bdcaad96fd956462bf3b2135ec5386d0a853..8ac261a1161acc529edf0b854035f6a2b1fcaaba 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -11,6 +11,7 @@
  */
 
 #include <stdio.h>
+#include <syslog.h>
 
 #include <haproxy/api.h>
 #include <haproxy/applet-t.h>
@@ -631,6 +632,35 @@ static int cli_parse_get_map(char **args, char *payload, struct appctx *appctx,
        return 1;
 }
 
+static int cli_parse_prepare_map(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       if (strcmp(args[1], "map") == 0 ||
+           strcmp(args[1], "acl") == 0) {
+               uint next_gen;
+               char *msg = 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;
+
+               /* lookup into the refs and check the map flag */
+               appctx->ctx.map.ref = pat_ref_lookup_ref(args[2]);
+               if (!appctx->ctx.map.ref ||
+                   !(appctx->ctx.map.ref->flags & appctx->ctx.map.display_flags)) {
+                       if (appctx->ctx.map.display_flags == PAT_REF_MAP)
+                               return cli_err(appctx, "Unknown map identifier. Please use #<id> or <file>.\n");
+                       else
+                               return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
+               }
+               next_gen = pat_ref_newgen(appctx->ctx.map.ref);
+               return cli_dynmsg(appctx, LOG_INFO, memprintf(&msg, "New version created: %u\n", next_gen));
+       }
+
+       return 0;
+}
+
 static void cli_release_show_map(struct appctx *appctx)
 {
        if (appctx->st2 == STAT_ST_LIST) {
@@ -1017,11 +1047,13 @@ static struct cli_kw_list cli_kws = {{ },{
        { { "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 },
+       { { "prepare","acl",NULL }, "prepare acl <id>: prepare a new version for atomic ACL replacement", cli_parse_prepare_map, NULL },
        { { "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 [@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 },
+       { { "prepare","map",NULL }, "prepare map <id>: prepare a new version for atomic map replacement", cli_parse_prepare_map, NULL },
        { { "set",   "map", NULL }, "set map        : modify map entry", cli_parse_set_map, NULL },
        { { "show",  "map", NULL }, "show map [@ver] [id] : report available maps or dump a map's contents", cli_parse_show_map, NULL },
        { { NULL }, NULL, NULL, NULL }