MEDIUM: vars: also support format strings in CLI's "set var" command
Most often "set var" on the CLI is used to set a string, and using only expressions is not always convenient, particularly when trying to concatenate variables sur as host names and paths. Now the "set var" command supports an optional keyword before the value to indicate its type. "expr" takes an expression just like before this patch, and "fmt" a format string, making it work like the "set-var-fmt" actions. The VTC was updated to include a test on the format string.
This commit is contained in:
parent
753d4db5f3
commit
e93bff4107
@ -2254,15 +2254,18 @@ set timeout cli <delay>
|
||||
some indicators without being disconnected. The delay is passed in seconds.
|
||||
|
||||
set var <name> <expression>
|
||||
set var <name> expr <expression>
|
||||
set var <name> fmt <format>
|
||||
Allows to set or overwrite the process-wide variable 'name' with the result
|
||||
of expression <expression>. Only process-wide variables may be used, so the
|
||||
name must begin with 'proc.' otherwise no variable will be set. The
|
||||
<expression> may only involve "internal" sample fetch keywords and converters
|
||||
even though the most likely useful ones will be str('something') or int().
|
||||
Note that the command line parser doesn't know about quotes, so any space in
|
||||
the expression must be preceded by a backslash. This command requires levels
|
||||
"operator" or "admin". This command is only supported on a CLI connection
|
||||
running in experimental mode (see "experimental-mode on").
|
||||
of expression <expression> or format string <format>. Only process-wide
|
||||
variables may be used, so the name must begin with 'proc.' otherwise no
|
||||
variable will be set. The <expression> and <format> may only involve
|
||||
"internal" sample fetch keywords and converters even though the most likely
|
||||
useful ones will be str('something'), int(), simple strings or references to
|
||||
other variables. Note that the command line parser doesn't know about quotes,
|
||||
so any space in the expression must be preceded by a backslash. This command
|
||||
requires levels "operator" or "admin". This command is only supported on a
|
||||
CLI connection running in experimental mode (see "experimental-mode on").
|
||||
|
||||
set weight <backend>/<server> <weight>[%]
|
||||
Change a server's weight to the value passed in argument. If the value ends
|
||||
|
@ -71,7 +71,7 @@ haproxy h1 -cli {
|
||||
}
|
||||
|
||||
haproxy h1 -cli {
|
||||
send "experimental-mode on; set var proc.str str(updated)"
|
||||
send "experimental-mode on; set var proc.str str(updating); set var proc.str fmt %[var(proc.str),regsub(ing,ed)]"
|
||||
expect ~ .*
|
||||
}
|
||||
|
||||
|
58
src/vars.c
58
src/vars.c
@ -1015,7 +1015,11 @@ static int vars_parse_cli_get_var(char **args, char *payload, struct appctx *app
|
||||
return cli_msg(appctx, LOG_INFO, trash.area);
|
||||
}
|
||||
|
||||
/* parse CLI's "set var <name> <expression>" */
|
||||
/* parse CLI's "set var <name>". It accepts:
|
||||
* - set var <name> <expression>
|
||||
* - set var <name> expr <expression>
|
||||
* - set var <name> fmt <format>
|
||||
*/
|
||||
static int vars_parse_cli_set_var(char **args, char *payload, struct appctx *appctx, void *private)
|
||||
{
|
||||
struct proxy px = {
|
||||
@ -1027,31 +1031,50 @@ static int vars_parse_cli_set_var(char **args, char *payload, struct appctx *app
|
||||
.arg.vars.scope = SCOPE_PROC,
|
||||
.from = ACT_F_CLI_PARSER,
|
||||
};
|
||||
enum obj_type objt = OBJ_TYPE_NONE;
|
||||
struct session *sess = NULL;
|
||||
enum act_parse_ret p_ret;
|
||||
char *old_arg2;
|
||||
char *tmp_arg2;
|
||||
const char *tmp_args[3];
|
||||
int tmp_arg;
|
||||
char *tmp_act;
|
||||
char *err = NULL;
|
||||
int arg = 2; // variable name
|
||||
int nberr;
|
||||
int use_fmt = 0;
|
||||
|
||||
LIST_INIT(&px.conf.args.list);
|
||||
|
||||
if (!cli_has_level(appctx, ACCESS_LVL_OPER))
|
||||
return 1;
|
||||
|
||||
if (!*args[2] || !*args[3])
|
||||
return cli_err(appctx, "Missing process-wide variable identifier and expression.\n");
|
||||
if (!*args[2])
|
||||
return cli_err(appctx, "Missing process-wide variable identifier.\n");
|
||||
|
||||
tmp_arg2 = NULL;
|
||||
if (!memprintf(&tmp_arg2, "set-var(%s)", args[2])) {
|
||||
if (!*args[3])
|
||||
return cli_err(appctx, "Missing either 'expr', 'fmt' or expression.\n");
|
||||
|
||||
if (*args[4]) {
|
||||
/* this is the long format */
|
||||
if (strcmp(args[3], "fmt") == 0)
|
||||
use_fmt = 1;
|
||||
else if (strcmp(args[3], "expr") != 0) {
|
||||
memprintf(&err, "'%s %s': arg type must be either 'expr' or 'fmt' but got '%s'.", args[0], args[1], args[3]);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
tmp_act = NULL;
|
||||
if (!memprintf(&tmp_act, "set-var%s(%s)", use_fmt ? "-fmt" : "", args[2])) {
|
||||
memprintf(&err, "memory allocation error.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* parse_store() will always return a message in <err> on error */
|
||||
old_arg2 = args[2]; args[2] = tmp_arg2;
|
||||
p_ret = parse_store((const char **)(args + 1), &arg, &px, &rule, &err);
|
||||
free(args[2]); args[2] = old_arg2;
|
||||
tmp_args[0] = tmp_act;
|
||||
tmp_args[1] = (*args[4]) ? args[4] : args[3];
|
||||
tmp_args[2] = "";
|
||||
tmp_arg = 1; // must point to the first arg after the action
|
||||
p_ret = parse_store(tmp_args, &tmp_arg, &px, &rule, &err);
|
||||
free(tmp_act);
|
||||
|
||||
if (p_ret != ACT_RET_PRS_OK)
|
||||
goto fail;
|
||||
@ -1069,8 +1092,17 @@ static int vars_parse_cli_set_var(char **args, char *payload, struct appctx *app
|
||||
goto fail;
|
||||
}
|
||||
|
||||
action_store(&rule, &px, NULL, NULL, 0);
|
||||
if (use_fmt && !(sess = session_new(&px, NULL, &objt))) {
|
||||
release_sample_expr(rule.arg.vars.expr);
|
||||
memprintf(&err, "memory allocation error.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
action_store(&rule, &px, sess, NULL, 0);
|
||||
release_sample_expr(rule.arg.vars.expr);
|
||||
if (sess)
|
||||
session_free(sess);
|
||||
|
||||
appctx->st0 = CLI_ST_PROMPT;
|
||||
return 0;
|
||||
fail:
|
||||
@ -1239,7 +1271,7 @@ INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
|
||||
/* register cli keywords */
|
||||
static struct cli_kw_list cli_kws = {{ },{
|
||||
{ { "get", "var", NULL }, "get var <name> : retrieve contents of a process-wide variable", vars_parse_cli_get_var, NULL },
|
||||
{ { "set", "var", NULL }, "set var <name> <expr> : set variable from an expression", vars_parse_cli_set_var, NULL, NULL, NULL, ACCESS_EXPERIMENTAL },
|
||||
{ { "set", "var", NULL }, "set var <name> [fmt|expr] {<fmt>|<expr>}: set variable from an expression or a format", vars_parse_cli_set_var, NULL, NULL, NULL, ACCESS_EXPERIMENTAL },
|
||||
{ { NULL }, NULL, NULL, NULL }
|
||||
}};
|
||||
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
|
||||
|
Loading…
x
Reference in New Issue
Block a user