MINOR: map/acl: make "add map/acl" support an optional version number
By passing a version number to "add map/acl", it becomes possible to atomically replace maps and ACLs. The principle is that a new version number is first retrieved by calling"prepare map/acl", and this version number is used with "add map" and "add acl". Newly added entries then remain invisible to the matching mechanism but are visible in "show map/acl" when the version number is specified, or may be cleard with "clear map/acl". Finally when the insertion is complete, a "commit map/acl" command must be issued, and the version is atomically updated so that there is no intermediate state with incomplete entries.
This commit is contained in:
parent
7a562ca809
commit
bb51c44d64
|
@ -1397,22 +1397,36 @@ abort ssl cert <filename>
|
||||||
|
|
||||||
See also "set ssl cert" and "commit ssl cert".
|
See also "set ssl cert" and "commit ssl cert".
|
||||||
|
|
||||||
add acl <acl> <pattern>
|
add acl [@<ver>] <acl> <pattern>
|
||||||
Add an entry into the acl <acl>. <acl> is the #<id> or the <file> returned by
|
Add an entry into the acl <acl>. <acl> is the #<id> or the <file> returned by
|
||||||
"show acl". This command does not verify if the entry already exists. This
|
"show acl". This command does not verify if the entry already exists. Entries
|
||||||
command cannot be used if the reference <acl> is a file also used with a map.
|
are added to the current version of the ACL, unless a specific version is
|
||||||
In this case, you must use the command "add map" in place of "add acl".
|
specified with "@<ver>". This version number must have preliminary been
|
||||||
|
allocated by "prepare acl", and it will be comprised between the versions
|
||||||
|
reported in "curr_ver" and "next_ver" on the output of "show acl". Entries
|
||||||
|
added with a specific version number will not match until a "commit acl"
|
||||||
|
operation is performed on them. They may however be consulted using the
|
||||||
|
"show acl @<ver>" command, and cleared using a "clear acl @<ver>" command.
|
||||||
|
This command cannot be used if the reference <acl> is a file also used with
|
||||||
|
a map. In this case, the "add map" command must be used instead.
|
||||||
|
|
||||||
add map <map> <key> <value>
|
add map [@<ver>] <map> <key> <value>
|
||||||
add map <map> <payload>
|
add map [@<ver>] <map> <payload>
|
||||||
Add an entry into the map <map> to associate the value <value> to the key
|
Add an entry into the map <map> to associate the value <value> to the key
|
||||||
<key>. This command does not verify if the entry already exists. It is
|
<key>. This command does not verify if the entry already exists. It is
|
||||||
mainly used to fill a map after a clear operation. Note that if the reference
|
mainly used to fill a map after a "clear" or "prepare" operation. Entries
|
||||||
<map> is a file and is shared with a map, this map will contain also a new
|
are added to the current version of the ACL, unless a specific version is
|
||||||
pattern entry. Using the payload syntax it is possible to add multiple
|
specified with "@<ver>". This version number must have preliminary been
|
||||||
key/value pairs by entering them on separate lines. On each new line, the
|
allocated by "prepare acl", and it will be comprised between the versions
|
||||||
first word is the key and the rest of the line is considered to be the value
|
reported in "curr_ver" and "next_ver" on the output of "show acl". Entries
|
||||||
which can even contains spaces.
|
added with a specific version number will not match until a "commit map"
|
||||||
|
operation is performed on them. They may however be consulted using the
|
||||||
|
"show map @<ver>" command, and cleared using a "clear acl @<ver>" command.
|
||||||
|
If the designated map is also used as an ACL, the ACL will only match the
|
||||||
|
<key> part and will ignore the <value> part. Using the payload syntax it is
|
||||||
|
possible to add multiple key/value pairs by entering them on separate lines.
|
||||||
|
On each new line, the first word is the key and the rest of the line is
|
||||||
|
considered to be the value which can even contains spaces.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
27
src/map.c
27
src/map.c
|
@ -796,6 +796,8 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
|
||||||
{
|
{
|
||||||
if (strcmp(args[1], "map") == 0 ||
|
if (strcmp(args[1], "map") == 0 ||
|
||||||
strcmp(args[1], "acl") == 0) {
|
strcmp(args[1], "acl") == 0) {
|
||||||
|
const char *gen = NULL;
|
||||||
|
uint genid = 0;
|
||||||
int ret;
|
int ret;
|
||||||
char *err;
|
char *err;
|
||||||
|
|
||||||
|
@ -805,6 +807,15 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
|
||||||
else
|
else
|
||||||
appctx->ctx.map.display_flags = PAT_REF_ACL;
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the keyword is "map", we expect:
|
/* If the keyword is "map", we expect:
|
||||||
* - three parameters if there is no payload
|
* - three parameters if there is no payload
|
||||||
* - one parameter if there is a payload
|
* - one parameter if there is a payload
|
||||||
|
@ -829,6 +840,16 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
|
||||||
return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
|
return cli_err(appctx, "Unknown ACL identifier. Please use #<id> or <file>.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gen) {
|
||||||
|
genid = str2uic(gen);
|
||||||
|
if ((int)(genid - appctx->ctx.map.ref->next_gen) > 0) {
|
||||||
|
if (appctx->ctx.map.display_flags == PAT_REF_MAP)
|
||||||
|
return cli_err(appctx, "Version number in the future, please use 'prepare map' before.\n");
|
||||||
|
else
|
||||||
|
return cli_err(appctx, "Version number in the future, please use 'prepare acl' before.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* The command "add acl" is prohibited if the reference
|
/* The command "add acl" is prohibited if the reference
|
||||||
* use samples.
|
* use samples.
|
||||||
*/
|
*/
|
||||||
|
@ -880,7 +901,7 @@ static int cli_parse_add_map(char **args, char *payload, struct appctx *appctx,
|
||||||
value = NULL;
|
value = NULL;
|
||||||
|
|
||||||
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
|
HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
|
||||||
ret = !!pat_ref_load(appctx->ctx.map.ref, appctx->ctx.map.ref->curr_gen, key, value, -1, &err);
|
ret = !!pat_ref_load(appctx->ctx.map.ref, gen ? genid : appctx->ctx.map.ref->curr_gen, key, value, -1, &err);
|
||||||
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
|
HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
@ -1107,14 +1128,14 @@ static int cli_parse_commit_map(char **args, char *payload, struct appctx *appct
|
||||||
/* register cli keywords */
|
/* register cli keywords */
|
||||||
|
|
||||||
static struct cli_kw_list cli_kws = {{ },{
|
static struct cli_kw_list cli_kws = {{ },{
|
||||||
{ { "add", "acl", NULL }, "add acl : add acl entry", cli_parse_add_map, NULL },
|
{ { "add", "acl", NULL }, "add acl [@ver] : add acl entry", cli_parse_add_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 },
|
{ { "clear", "acl", NULL }, "clear acl [@ver] <id> : clear the content of this acl", cli_parse_clear_map, cli_io_handler_clear_map, NULL },
|
||||||
{ { "commit","acl", NULL }, "commit acl @<ver> <id> : commit the ACL at this version", cli_parse_commit_map, cli_io_handler_clear_map, NULL },
|
{ { "commit","acl", NULL }, "commit acl @<ver> <id> : commit the ACL at this version", cli_parse_commit_map, cli_io_handler_clear_map, NULL },
|
||||||
{ { "del", "acl", NULL }, "del acl : delete acl entry", cli_parse_del_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 },
|
{ { "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 },
|
{ { "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 },
|
{ { "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 },
|
{ { "add", "map", NULL }, "add map [@ver] : 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 },
|
{ { "clear", "map", NULL }, "clear map [@ver] <id> : clear the content of this map", cli_parse_clear_map, cli_io_handler_clear_map, NULL },
|
||||||
{ { "commit","map", NULL }, "commit map @<ver> <id> : commit the map at this version", cli_parse_commit_map, cli_io_handler_clear_map, NULL },
|
{ { "commit","map", NULL }, "commit map @<ver> <id> : commit the map at this version", cli_parse_commit_map, cli_io_handler_clear_map, NULL },
|
||||||
{ { "del", "map", NULL }, "del map : delete map entry", cli_parse_del_map, NULL },
|
{ { "del", "map", NULL }, "del map : delete map entry", cli_parse_del_map, NULL },
|
||||||
|
|
Loading…
Reference in New Issue