mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-10 19:21:37 +00:00
MEDIUM: cli: add a new experimental "set var" command
set var <name> <expression> 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 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"). Just like for "set-var" in the global section, the command uses a temporary dummy proxy to create a temporary "set-var(name)" rule to assign the value. The reg test was updated to verify that an updated global variable is properly reflected in subsequent HTTP responses.
This commit is contained in:
parent
c35eb38f1d
commit
b8bd1ee893
@ -1776,6 +1776,17 @@ get var <name>
|
||||
'proc.' otherwise no variable will be found. This command requires levels
|
||||
"operator" or "admin".
|
||||
|
||||
set var <name> <expression>
|
||||
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 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 <backend>/<server>
|
||||
Report the current weight and the initial weight of server <server> in
|
||||
backend <backend> or an error if either doesn't exist. The initial weight is
|
||||
|
@ -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
|
||||
|
63
src/vars.c
63
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 <name> <expression>" */
|
||||
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 <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;
|
||||
|
||||
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 <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 },
|
||||
{ { NULL }, NULL, NULL, NULL }
|
||||
}};
|
||||
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
|
||||
|
Loading…
Reference in New Issue
Block a user