]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: tools: support environment variables in addresses
authorWilly Tarreau <w@1wt.eu>
Mon, 11 Mar 2013 00:20:04 +0000 (01:20 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 11 Mar 2013 00:30:02 +0000 (01:30 +0100)
Now that all addresses are parsed using str2sa_range(), it becomes easy
to add support for environment variables and use them everywhere an address
is needed. Environment variables are used as $VAR or ${VAR} as in shell.
Any number of variables may compose an address, allowing various fantasies
such as "fd@${FD_HTTP}" or "${LAN_DC1}.1:80".

These ones are usable in logs, bind, servers, peers, stats socket, source,
dispatch, and check address.

doc/configuration.txt
include/common/standard.h
src/standard.c

index 86d88a9b0c3aee27a0ce1fb63a48e328c680f5ed..525452765109f76a5324165848653f8c13f445a5 100644 (file)
@@ -562,6 +562,11 @@ log <address> <facility> [max level [min level]]
           the chroot) and uid/gid (be sure the path is appropriately
           writeable).
 
+        Any part of the address string may reference any number of environment
+        variables by preceding their name with a dollar sign ('$') and
+        optionally enclosing them with braces ('{}'), similarly to what is done
+        in Bourne shell.
+
   <facility> must be one of the 24 standard syslog facilities :
 
           kern   user   mail   daemon auth   syslog lpr    news
@@ -1021,6 +1026,10 @@ peer <peername> <ip>:<port>
   peer name. This makes it easier to maintain coherent configuration files
   across all peers.
 
+  Any part of the address string may reference any number of environment
+  variables by preceding their name with a dollar sign ('$') and optionally
+  enclosing them with braces ('{}'), similarly to what is done in Bourne shell.
+
   Example:
     peers mypeers
         peer haproxy1 192.168.0.1:1024
@@ -1619,6 +1628,10 @@ bind /<path> [, ...] [param*]
                     - 'fd@<n>' -> use file descriptor <n> inherited from the
                       parent. The fd must be bound and may or may not already
                       be listening.
+                  Any part of the address string may reference any number of
+                  environment variables by preceding their name with a dollar
+                  sign ('$') and optionally enclosing them with braces ('{}'),
+                  similarly to what is done in Bourne shell.
 
     <port_range>  is either a unique TCP port, or a port range for which the
                   proxy will accept connections for the IP address specified
@@ -1675,6 +1688,9 @@ bind /<path> [, ...] [param*]
             bind ipv4@public_ssl:443 ssl crt /etc/haproxy/site.pem
             bind unix@ssl-frontend.sock user root mode 600 accept-proxy
 
+        listen external_bind_app1
+            bind fd@${FD_APP1}
+
   See also : "source", "option forwardfor", "unix-bind" and the PROXY protocol
              documentation, and section 5 about bind options.
 
@@ -2829,6 +2845,11 @@ no log
                  inside the chroot) and uid/gid (be sure the path is
                  appropriately writeable).
 
+               Any part of the address string may reference any number of
+               environment variables by preceding their name with a dollar
+               sign ('$') and optionally enclosing them with braces ('{}'),
+               similarly to what is done in Bourne shell.
+
     <facility> must be one of the 24 standard syslog facilities :
 
                  kern   user   mail   daemon auth   syslog lpr    news
@@ -2862,6 +2883,8 @@ no log
     log global
     log 127.0.0.1:514 local0 notice         # only send important events
     log 127.0.0.1:514 local0 notice notice  # same but limit output level
+    log ${LOCAL_SYSLOG}:514 local0 notice   # send to local server
+
 
 log-format <string>
    Allows you to custom a log line.
@@ -5094,6 +5117,10 @@ server <name> <address>[:[port]] [param*]
                     - 'ipv4@'  -> address is always IPv4
                     - 'ipv6@'  -> address is always IPv6
                     - 'unix@'  -> address is a path to a local unix socket
+              Any part of the address string may reference any number of
+              environment variables by preceding their name with a dollar
+              sign ('$') and optionally enclosing them with braces ('{}'),
+              similarly to what is done in Bourne shell.
 
     <port>    is an optional port specification. If set, all connections will
               be sent to this port. If unset, the same port the client
@@ -5109,6 +5136,9 @@ server <name> <address>[:[port]] [param*]
         server first  10.1.1.1:1080 cookie first  check inter 1000
         server second 10.1.1.2:1080 cookie second check inter 1000
         server transp ipv4@
+        server backup ${SRV_BACKUP}:1080 backup
+        server www1_dc1 ${LAN_DC1}.101:80
+        server www1_dc2 ${LAN_DC2}.101:80
 
   See also: "default-server", "http-send-name-header" and section 5 about
              server options
@@ -5133,6 +5163,10 @@ source <addr>[:<port>] [interface <name>]
                 - 'ipv4@' -> address is always IPv4
                 - 'ipv6@' -> address is always IPv6
                 - 'unix@' -> address is a path to a local unix socket
+              Any part of the address string may reference any number of
+              environment variables by preceding their name with a dollar
+              sign ('$') and optionally enclosing them with braces ('{}'),
+              similarly to what is done in Bourne shell.
 
     <port>    is an optional port. It is normally not needed but may be useful
               in some very specific contexts. The default value of zero means
index f9f21b06a967ccdad092be9f8452f4b4abdb2ae7..8e88ee547406841cdcfbe8b9a1b606ce2948cb2d 100644 (file)
@@ -732,6 +732,14 @@ char *memprintf(char **out, const char *format, ...)
  */
 char *indent_msg(char **out, int level);
 
+/* Convert occurrences of environment variables in the input string to their
+ * corresponding value. A variable is identified as a series of alphanumeric
+ * characters or underscores following a '$' sign. The <in> string must be
+ * free()able. NULL returns NULL. The resulting string might be reallocated if
+ * some expansion is made.
+ */
+char *env_expand(char *in);
+
 /* debugging macro to emit messages using write() on fd #-1 so that strace sees
  * them.
  */
index cc22ba7fc16430e79a152c0443d448fe2e57f0c9..7a6ca1129e4d42e22ba5902234f41b04fa896e7d 100644 (file)
@@ -655,7 +655,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, char
 
        portl = porth = porta = 0;
 
-       str2 = back = strdup(str);
+       str2 = back = env_expand(strdup(str));
        if (str2 == NULL) {
                memprintf(err, "out of memory in '%s'\n", __FUNCTION__);
                goto out;
@@ -688,7 +688,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, char
                ((struct sockaddr_in *)&ss)->sin_addr.s_addr = strtol(str2, &endptr, 10);
 
                if (!*str2 || *endptr) {
-                       memprintf(err, "file descriptor '%s' is not a valid integer\n", str2);
+                       memprintf(err, "file descriptor '%s' is not a valid integer in '%s'\n", str2, str);
                        goto out;
                }
 
@@ -750,7 +750,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, char
                        porta = porth;
                }
                else if (*port1) { /* other any unexpected char */
-                       memprintf(err, "invalid character '%c' in port number '%s'\n", *port1, port1);
+                       memprintf(err, "invalid character '%c' in port number '%s' in '%s'\n", *port1, port1, str);
                        goto out;
                }
                set_host_port(&ss, porta);
@@ -1996,6 +1996,83 @@ char *indent_msg(char **out, int level)
        return ret;
 }
 
+/* Convert occurrences of environment variables in the input string to their
+ * corresponding value. A variable is identified as a series of alphanumeric
+ * characters or underscores following a '$' sign. The <in> string must be
+ * free()able. NULL returns NULL. The resulting string might be reallocated if
+ * some expansion is made. Variable names may also be enclosed into braces if
+ * needed (eg: to concatenate alphanum characters).
+ */
+char *env_expand(char *in)
+{
+       char *txt_beg;
+       char *out;
+       char *txt_end;
+       char *var_beg;
+       char *var_end;
+       char *value;
+       char *next;
+       int out_len;
+       int val_len;
+
+       if (!in)
+               return in;
+
+       value = out = NULL;
+       out_len = 0;
+
+       txt_beg = in;
+       do {
+               /* look for next '$' sign in <in> */
+               for (txt_end = txt_beg; *txt_end && *txt_end != '$'; txt_end++);
+
+               if (!*txt_end && !out) /* end and no expansion performed */
+                       return in;
+
+               val_len = 0;
+               next = txt_end;
+               if (*txt_end == '$') {
+                       char save;
+
+                       var_beg = txt_end + 1;
+                       if (*var_beg == '{')
+                               var_beg++;
+
+                       var_end = var_beg;
+                       while (isalnum((int)(unsigned char)*var_end) || *var_end == '_') {
+                               var_end++;
+                       }
+
+                       next = var_end;
+                       if (*var_end == '}' && (var_beg > txt_end + 1))
+                               next++;
+
+                       /* get value of the variable name at this location */
+                       save = *var_end;
+                       *var_end = '\0';
+                       value = getenv(var_beg);
+                       *var_end = save;
+                       val_len = value ? strlen(value) : 0;
+               }
+
+               out = realloc(out, out_len + (txt_end - txt_beg) + val_len + 1);
+               if (txt_end > txt_beg) {
+                       memcpy(out + out_len, txt_beg, txt_end - txt_beg);
+                       out_len += txt_end - txt_beg;
+               }
+               if (val_len) {
+                       memcpy(out + out_len, value, val_len);
+                       out_len += val_len;
+               }
+               out[out_len] = 0;
+               txt_beg = next;
+       } while (*txt_beg);
+
+       /* here we know that <out> was allocated and that we don't need <in> anymore */
+       free(in);
+       return out;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 8