]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: vars: add a "set-var-fmt" directive to the global section
authorWilly Tarreau <w@1wt.eu>
Fri, 3 Sep 2021 07:02:47 +0000 (09:02 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 3 Sep 2021 09:01:48 +0000 (11:01 +0200)
Just like the set-var-fmt action for tcp/http rules, the set-var-fmt
directive in global sections allows to pre-set process-wide variables
using a format string instead of a sample expression. This is often
more convenient when it is required to concatenate multiple fields,
or when emitting just one word.

doc/configuration.txt
reg-tests/sample_fetches/vars.vtc
src/vars.c

index 583610f75f07839ad631e79799b473ce4afbd36b..f6641750d0ff0385a4fd3942b64410cf0525e7a6 100644 (file)
@@ -1750,7 +1750,7 @@ set-var <var-name> <expr>
   '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
+  those using internal data, typically 'int(value)' or 'str(value)'. It is
   possible to reference previously allocated variables as well. These variables
   will then be readable (and modifiable) from the regular rule sets.
 
@@ -1760,6 +1760,23 @@ set-var <var-name> <expr>
           set-var proc.prio int(100)
           set-var proc.threshold int(200),sub(proc.prio)
 
+set-var-fmt <var-name> <fmt>
+  Sets the process-wide variable '<var-name>' to the string resulting from the
+  evaluation of the log-format <fmt>. The variable '<var-name>' may only be a
+  process-wide variable (using the 'proc.' prefix). It works exactly like the
+  'set-var-fmt' 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 is possible to reference previously allocated variables as well. These
+  variables will then be readable (and modifiable) from the regular rule sets.
+  Please see section 8.2.4 for details on the log-format syntax.
+
+  Example:
+      global
+          set-var-fmt proc.current_state "primary"
+          set-var-fmt proc.bootid        "%pid|%t"
+
 setenv <name> <value>
   Sets environment variable <name> to value <value>. If the variable exists, it
   is overwritten. The changes immediately take effect so that the next line in
index 95ab68d89130ebf0b2155add5c114fbf26697875..82d7718bef25169d64a44eabbc22f9e8d3637ba8 100644 (file)
@@ -10,7 +10,7 @@ haproxy h1 -conf {
         set-var proc.str1  str("this is")
         set-var proc.str2  str("a string")
         set-var proc.str   var(proc.str1)
-        set-var proc.str   str(""),concat("",proc.str," a string")
+        set-var-fmt proc.str "%[var(proc.str)] a string"
         set-var proc.uuid  uuid()
 
     defaults
index d4f41199447220aa2e06e588298515b660f53df6..168ead671c797f7df1e0a6b2abea7b2f83962307 100644 (file)
@@ -12,6 +12,7 @@
 #include <haproxy/list.h>
 #include <haproxy/log.h>
 #include <haproxy/sample.h>
+#include <haproxy/session.h>
 #include <haproxy/stream-t.h>
 #include <haproxy/tcp_rules.h>
 #include <haproxy/tcpcheck.h>
@@ -894,6 +895,7 @@ static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy
  * 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 <name> <expression>
+ *    set-var-fmt <name> <fmt>
  * Note that parse_store() expects "set-var(name) <expression>" so we have to
  * temporarily replace the keyword here.
  */
@@ -910,21 +912,29 @@ static int vars_parse_global_set_var(char **args, int section_type, struct proxy
                .arg.vars.scope = SCOPE_PROC,
                .from = ACT_F_CFG_PARSER,
        };
+       enum obj_type objt = OBJ_TYPE_NONE;
+       struct session *sess = NULL;
        enum act_parse_ret p_ret;
        char *old_arg1;
        char *tmp_arg1;
        int arg = 2; // variable name
        int ret = -1;
+       int use_fmt = 0;
 
        LIST_INIT(&px.conf.args.list);
 
+       use_fmt = strcmp(args[0], "set-var-fmt") == 0;
+
        if (!*args[1] || !*args[2]) {
-               memprintf(err, "'%s' requires a process-wide variable name ('proc.<name>') and a sample expression.", args[0]);
+               if (use_fmt)
+                       memprintf(err, "'%s' requires a process-wide variable name ('proc.<name>') and a format string.", args[0]);
+               else
+                       memprintf(err, "'%s' requires a process-wide variable name ('proc.<name>') and a sample expression.", args[0]);
                goto end;
        }
 
        tmp_arg1 = NULL;
-       if (!memprintf(&tmp_arg1, "set-var(%s)", args[1]))
+       if (!memprintf(&tmp_arg1, "set-var%s(%s)", use_fmt ? "-fmt" : "", args[1]))
                goto end;
 
        /* parse_store() will always return a message in <err> on error */
@@ -946,8 +956,16 @@ static int vars_parse_global_set_var(char **args, int section_type, struct proxy
                goto end;
        }
 
-       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, "'%s': out of memory when trying to set variable '%s' in the global section.", args[0], args[1]);
+               goto end;
+       }
+
+       action_store(&rule, &px, sess, NULL, 0);
        release_sample_expr(rule.arg.vars.expr);
+       if (sess)
+               session_free(sess);
 
        ret = 0;
  end:
@@ -1205,6 +1223,7 @@ 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, "set-var-fmt",          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   },