diff --git a/doc/configuration.txt b/doc/configuration.txt index aef9b4522..0f9e31aef 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -923,6 +923,7 @@ The following keywords are supported in the "global" section : - ulimit-n - user - set-dumpable + - set-var - setenv - stats - ssl-default-bind-ciphers @@ -1598,6 +1599,23 @@ server-state-file configuration. See also "server-state-base" and "show servers state", "load-server-state-from-file" and "server-state-file-name" +set-var + Sets the process-wide variable '' to the result of the evaluation + of the sample expression . The variable '' may only be a + process-wide variable (using the 'proc.' prefix). It works exactly like the + 'set-var' action in TCP or HTTP rules except that the expression is evaluated + at configuration parsing time and that the variable is instantly set. The + sample fetch functions and converters permitted in the expression are only + those using internal data, typically 'int(value)' or 'str(value)'. It's is + possible to reference previously allocated variables as well. These variables + will then be readable (and modifiable) from the regular rule sets. + + Example: + global + set-var proc.current_state str(primary) + set-var proc.prio int(100) + set-var proc.threshold int(200),sub(proc.prio) + setenv Sets environment variable to value . If the variable exists, it is overwritten. The changes immediately take effect so that the next line in diff --git a/src/vars.c b/src/vars.c index 1077a798e..5c8d45e39 100644 --- a/src/vars.c +++ b/src/vars.c @@ -718,7 +718,8 @@ static int conv_check_var(struct arg *args, struct sample_conv *conv, * * It returns ACT_RET_PRS_ERR if fails and is filled with an error * message. Otherwise, it returns ACT_RET_PRS_OK and the variable - * is filled with the pointer to the expression to execute. + * is filled with the pointer to the expression to execute. The proxy is + * only used to retrieve the ->conf entries. */ static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy *px, struct act_rule *rule, char **err) @@ -799,6 +800,71 @@ static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy return ACT_RET_PRS_OK; } + +/* parses a global "set-var" directive. It will create a temporary rule and + * expression that are parsed, processed, and released on the fly so that we + * respect the real set-var syntax. These directives take the following format: + * set-var + * Note that parse_store() expects "set-var(name) " so we have to + * temporarily replace the keyword here. + */ +static int vars_parse_global_set_var(char **args, int section_type, struct proxy *curpx, + const struct proxy *defpx, const char *file, int line, + char **err) +{ + struct proxy px = { + .id = "CLI", + .conf.args.file = file, + .conf.args.line = line, + }; + struct act_rule rule = { + .arg.vars.scope = SCOPE_PROC, + .from = ACT_F_CFG_PARSER, + }; + enum act_parse_ret p_ret; + char *old_arg1; + char *tmp_arg1; + int arg = 2; // variable name + int ret = -1; + + LIST_INIT(&px.conf.args.list); + + if (!*args[1] || !*args[2]) { + memprintf(err, "'%s' requires a process-wide variable name ('proc.') and a sample expression.", args[0]); + goto end; + } + + tmp_arg1 = NULL; + if (!memprintf(&tmp_arg1, "set-var(%s)", args[1])) + goto end; + + /* parse_store() will always return a message in on error */ + old_arg1 = args[1]; args[1] = tmp_arg1; + p_ret = parse_store((const char **)args, &arg, &px, &rule, err); + free(args[1]); args[1] = old_arg1; + + if (p_ret != ACT_RET_PRS_OK) + goto end; + + if (rule.arg.vars.scope != SCOPE_PROC) { + memprintf(err, "'%s': cannot set variable '%s', only scope 'proc' is permitted in the global section.", args[0], args[1]); + goto end; + } + + if (smp_resolve_args(&px, err) != 0) { + release_sample_expr(rule.arg.vars.expr); + indent_msg(err, 2); + goto end; + } + + action_store(&rule, &px, NULL, NULL, 0); + release_sample_expr(rule.arg.vars.expr); + + ret = 0; + end: + return ret; +} + 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) @@ -937,6 +1003,7 @@ static struct action_kw_list http_after_res_kws = { { }, { INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_kws); static struct cfg_kw_list cfg_kws = {{ },{ + { CFG_GLOBAL, "set-var", vars_parse_global_set_var }, { CFG_GLOBAL, "tune.vars.global-max-size", vars_max_size_global }, { CFG_GLOBAL, "tune.vars.proc-max-size", vars_max_size_proc }, { CFG_GLOBAL, "tune.vars.sess-max-size", vars_max_size_sess },