diff --git a/doc/management.txt b/doc/management.txt index bd3622aa0..c7eb7fff4 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -1776,6 +1776,17 @@ get var 'proc.' otherwise no variable will be found. This command requires levels "operator" or "admin". +set var + 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 preceeded 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"). + get weight / Report the current weight and the initial weight of server in backend or an error if either doesn't exist. The initial weight is diff --git a/reg-tests/sample_fetches/vars.vtc b/reg-tests/sample_fetches/vars.vtc index b57156ce9..01e25b96d 100644 --- a/reg-tests/sample_fetches/vars.vtc +++ b/reg-tests/sample_fetches/vars.vtc @@ -64,3 +64,15 @@ haproxy h1 -cli { send "get var proc.int5" expect ~ "^proc.int5: type=sint value=<20>$" } + +haproxy h1 -cli { + send "experimental-mode on; set var proc.str str(updated)" + expect ~ .* +} + +client c3 -connect ${h1_fe1_sock} { + txreq -req GET -url /req3_1 + rxresp + expect resp.status == 200 + expect resp.http.x-var ~ "proc=40 sess=40 req=20 str=updated uuid=[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*-[0-9a-f]*" +} -run diff --git a/src/vars.c b/src/vars.c index 11efd55a4..cf92005f5 100644 --- a/src/vars.c +++ b/src/vars.c @@ -912,6 +912,68 @@ 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 " */ +static int vars_parse_cli_set_var(char **args, char *payload, struct appctx *appctx, void *private) +{ + struct proxy px = { + .id = "CLI", + .conf.args.file = "CLI", + .conf.args.line = 0, + }; + struct act_rule rule = { + .arg.vars.scope = SCOPE_PROC, + .from = ACT_F_CLI_PARSER, + }; + enum act_parse_ret p_ret; + char *old_arg2; + char *tmp_arg2; + char *err = NULL; + int arg = 2; // variable name + int nberr; + + 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"); + + tmp_arg2 = NULL; + if (!memprintf(&tmp_arg2, "set-var(%s)", 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; + + if (p_ret != ACT_RET_PRS_OK) + goto fail; + + if (rule.arg.vars.scope != SCOPE_PROC) { + memprintf(&err, "'%s %s': cannot set variable '%s', only scope 'proc' is permitted in the global section.", args[0], args[1], args[2]); + goto fail; + } + + err = NULL; + nberr = smp_resolve_args(&px, &err); + if (nberr) { + release_sample_expr(rule.arg.vars.expr); + indent_msg(&err, 2); + goto fail; + } + + action_store(&rule, &px, NULL, NULL, 0); + release_sample_expr(rule.arg.vars.expr); + appctx->st0 = CLI_ST_PROMPT; + return 0; + fail: + return cli_dynerr(appctx, err); +} + static int vars_max_size(char **args, int section_type, struct proxy *curpx, const struct proxy *defpx, const char *file, int line, char **err, unsigned int *limit) @@ -1066,6 +1128,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 }, { { NULL }, NULL, NULL, NULL } }}; INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);