diff --git a/doc/management.txt b/doc/management.txt index 58d06e48c..c7a8e4884 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -2254,15 +2254,18 @@ set timeout cli some indicators without being disconnected. The delay is passed in seconds. set var +set var expr +set var fmt Allows to set or overwrite the process-wide variable 'name' with the result - of expression . Only process-wide variables may be used, so the - name must begin with 'proc.' otherwise no variable will be set. The - 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 or format string . Only process-wide + variables may be used, so the name must begin with 'proc.' otherwise no + variable will be set. The and 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 / [%] Change a server's weight to the value passed in argument. If the value ends diff --git a/reg-tests/sample_fetches/vars.vtc b/reg-tests/sample_fetches/vars.vtc index 82d7718be..5dc7b4400 100644 --- a/reg-tests/sample_fetches/vars.vtc +++ b/reg-tests/sample_fetches/vars.vtc @@ -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 ~ .* } diff --git a/src/vars.c b/src/vars.c index 168ead671..6208093d2 100644 --- a/src/vars.c +++ b/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 " */ +/* parse CLI's "set var ". It accepts: + * - set var + * - set var expr + * - set var fmt + */ 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 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 : retrieve contents of a process-wide variable", vars_parse_cli_get_var, NULL }, - { { "set", "var", NULL }, "set var : set variable from an expression", vars_parse_cli_set_var, NULL, NULL, NULL, ACCESS_EXPERIMENTAL }, + { { "set", "var", NULL }, "set var [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);