]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: config: support some pseudo-variables for file/line/section
authorWilly Tarreau <w@1wt.eu>
Thu, 6 May 2021 08:25:11 +0000 (10:25 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 6 May 2021 08:36:38 +0000 (10:36 +0200)
The new pseudo-variables ".FILE", ".LINE" and ".SECTION" will be resolved
on the fly by the config parser and will respectively retrieve the current
configuration file name, the current line number and the current section
being parsed. This may help emit logs, errors, and debugging information
(e.g. which rule matched).

The '.' in the first char was reserved for such pseudo-variables and no
other variable is permitted. This will allow to add support for new ones
in the future if they prove to be useful (e.g. randoms/uuid for secret
keying or automatic naming of configuration objects).

doc/configuration.txt
src/tools.c

index 12d44c5472b7d49f4e070b05c7f5d5d1710d4cad..a6af2f267df9c4a54ab82436bb7e91b8bf0b45ef 100644 (file)
@@ -746,6 +746,29 @@ file, or could be inherited by a program (See 3.7. Programs):
 * HAPROXY_MASTER_CLI: In master-worker mode, listeners addresses of the master
   CLI, separated by semicolons.
 
+In addition, some pseudo-variables are internally resolved and may be used as
+regular variables. Pseudo-variables always start with a dot ('.'), and are the
+only ones where the dot is permitted. The current list of pseudo-variables is:
+
+* .FILE: the name of the configuration file currently being parsed.
+
+* .LINE: the line number of the configuration file currently being parsed,
+  starting at one.
+
+* .SECTION: the name of the section currently being parsed, or its type if the
+  section doesn't have a name (e.g. "global"), or an empty string before the
+  first section.
+
+These variables are resolved at the location where they are parsed. For example
+if a ".LINE" variable is used in a "log-format" directive located in a defaults
+section, its line number will be resolved before parsing and compiling the
+"log-format" directive, so this same line number will be reused by subsequent
+proxies.
+
+This way it is possible to emit information to help locate a rule in variables,
+logs, error statuses, health checks, header values, or even to use line numbers
+to name some config objects like servers for example.
+
 See also "external-check command" for other variables.
 
 
index 056c9ca77393c82c97a928e561dd9a2d01b1c7b2..c45358570bfbabf8fa7977205330316676b8da5a 100644 (file)
@@ -5300,14 +5300,14 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg
                         */
                        char *var_name;
                        char save_char;
-                       char *value;
+                       const char *value;
 
                        in++;
 
                        if (*in == '{')
                                brace = in++;
 
-                       if (!isalpha((unsigned char)*in) && *in != '_') {
+                       if (!isalpha((unsigned char)*in) && *in != '_' && *in != '.') {
                                /* unacceptable character in variable name */
                                err |= PARSE_ERR_VARNAME;
                                if (errptr)
@@ -5316,12 +5316,31 @@ uint32_t parse_line(char *in, char *out, size_t *outlen, char **args, int *nbarg
                        }
 
                        var_name = in;
+                       if (*in == '.')
+                               in++;
                        while (isalnum((unsigned char)*in) || *in == '_')
                                in++;
 
                        save_char = *in;
                        *in = '\0';
-                       value = getenv(var_name);
+                       if (unlikely(*var_name == '.')) {
+                               /* internal pseudo-variables */
+                               if (strcmp(var_name, ".LINE") == 0)
+                                       value = ultoa(global.cfg_curr_line);
+                               else if (strcmp(var_name, ".FILE") == 0)
+                                       value = global.cfg_curr_file;
+                               else if (strcmp(var_name, ".SECTION") == 0)
+                                       value = global.cfg_curr_section;
+                               else {
+                                       /* unsupported internal variable name */
+                                       err |= PARSE_ERR_VARNAME;
+                                       if (errptr)
+                                               *errptr = var_name;
+                                       goto leave;
+                               }
+                       } else {
+                               value = getenv(var_name);
+                       }
                        *in = save_char;
 
                        /* support for '[*]' sequence to force word expansion,