]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: cli: add a new "show env" command
authorWilly Tarreau <w@1wt.eu>
Tue, 16 Feb 2016 10:27:28 +0000 (11:27 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 16 Feb 2016 10:43:03 +0000 (11:43 +0100)
Using environment variables in configuration files can make troubleshooting
complicated because there's no easy way to verify that the variables are
correct. This patch introduces a new "show env" command which displays the
whole environment on the CLI, one variable per line.

The socket must at least have level operator to display the environment.

doc/management.txt
include/types/applet.h
src/dumpstats.c

index 466f40e7b63cdbb26a7b75eaf796844b680e9de1..1b677be9b3839d87620d124b24ec3bc9ecdfe3d5 100644 (file)
@@ -1472,6 +1472,16 @@ set weight <backend>/<server> <weight>[%]
   "admin". Both the backend and the server may be specified either by their
   name or by their numeric ID, prefixed with a sharp ('#').
 
+show env [<name>]
+  Dump one or all environment variables known by the process. Without any
+  argument, all variables are dumped. With an argument, only the specified
+  variable is dumped if it exists. Otherwise "Variable not found" is emitted.
+  Variables are dumped in the same format as they are stored or returned by the
+  "env" utility, that is, "<name>=<value>". This can be handy when debugging
+  certain configuration files making heavy use of environment variables to
+  ensure that they contain the expected values. This command is restricted and
+  can only be issued on sockets configured for levels "operator" or "admin".
+
 show errors [<iid>]
   Dump last known request and response errors collected by frontends and
   backends. If <iid> is specified, the limit the dump to errors concerning
index 2e1626a79d1fd65d3eea0345ea6e070402764b7a..562575f020d7de26094763cb0ad50657684c9226 100644 (file)
@@ -133,6 +133,9 @@ struct appctx {
                struct {
                        struct proxy *backend;
                } server_state;
+               struct {
+                       char **var;
+               } env;
        } ctx;                                  /* used by stats I/O handlers to dump the stats */
 };
 
index b868ef56e9caf365b226d05b6167731044a0e8fb..8b55fe3a202c451a8e4c47b38714144e34ae7bf3 100644 (file)
@@ -94,6 +94,7 @@ enum {
        STAT_CLI_O_RESOLVERS,/* dump a resolver's section nameservers counters */
        STAT_CLI_O_SERVERS_STATE, /* dump server state and changing information */
        STAT_CLI_O_BACKEND,  /* dump backend list */
+       STAT_CLI_O_ENV,      /* dump environment */
 };
 
 /* Actions available for the stats admin forms */
@@ -130,6 +131,7 @@ enum {
 };
 
 static int stats_dump_backend_to_buffer(struct stream_interface *si);
+static int stats_dump_env_to_buffer(struct stream_interface *si);
 static int stats_dump_info_to_buffer(struct stream_interface *si);
 static int stats_dump_servers_state_to_buffer(struct stream_interface *si);
 static int stats_dump_pools_to_buffer(struct stream_interface *si);
@@ -191,6 +193,7 @@ static const char stats_sock_usage_msg[] =
        "  prompt         : toggle interactive mode with prompt\n"
        "  quit           : disconnect\n"
        "  show backend   : list backends in the current running config\n"
+       "  show env [var] : dump environment variables known to the process\n"
        "  show info      : report information about the running process\n"
        "  show pools     : report information about the memory pools usage\n"
        "  show stat      : report counters for each proxy and server\n"
@@ -1162,7 +1165,35 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
                        appctx->st2 = STAT_ST_INIT;
                        appctx->st0 = STAT_CLI_O_BACKEND;
                }
-                else if (strcmp(args[1], "stat") == 0) {
+               else if (strcmp(args[1], "env") == 0) {
+                       extern char **environ;
+
+                       if (strm_li(s)->bind_conf->level < ACCESS_LVL_OPER) {
+                               appctx->ctx.cli.msg = stats_permission_denied_msg;
+                               appctx->st0 = STAT_CLI_PRINT;
+                               return 1;
+                       }
+                       appctx->ctx.env.var = environ;
+                       appctx->st2 = STAT_ST_INIT;
+                       appctx->st0 = STAT_CLI_O_ENV; // stats_dump_env_to_buffer
+
+                       if (*args[2]) {
+                               int len = strlen(args[2]);
+
+                               for (; *appctx->ctx.env.var; appctx->ctx.env.var++) {
+                                       if (strncmp(*appctx->ctx.env.var, args[2], len) == 0 &&
+                                           (*appctx->ctx.env.var)[len] == '=')
+                                               break;
+                               }
+                               if (!*appctx->ctx.env.var) {
+                                       appctx->ctx.cli.msg = "Variable not found\n";
+                                       appctx->st0 = STAT_CLI_PRINT;
+                                       return 1;
+                               }
+                               appctx->st2 = STAT_ST_END;
+                       }
+               }
+               else if (strcmp(args[1], "stat") == 0) {
                        if (strcmp(args[2], "resolvers") == 0) {
                                struct dns_resolvers *presolvers;
 
@@ -2589,6 +2620,10 @@ static void cli_io_handler(struct appctx *appctx)
                                        appctx->st0 = STAT_CLI_PROMPT;
                                break;
 #endif
+                       case STAT_CLI_O_ENV:    /* environment dump */
+                               if (stats_dump_env_to_buffer(si))
+                                       appctx->st0 = STAT_CLI_PROMPT;
+                               break;
                        default: /* abnormal state */
                                si->flags |= SI_FL_ERR;
                                break;
@@ -6655,6 +6690,38 @@ static int stats_dump_errors_to_buffer(struct stream_interface *si)
        return 1;
 }
 
+/* This function dumps all environmnent variables to the buffer. It returns 0
+ * if the output buffer is full and it needs to be called again, otherwise
+ * non-zero. Dumps only one entry if st2 == STAT_ST_END.
+ */
+static int stats_dump_env_to_buffer(struct stream_interface *si)
+{
+       struct appctx *appctx = __objt_appctx(si->end);
+
+       if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
+               return 1;
+
+       chunk_reset(&trash);
+
+       /* we have two inner loops here, one for the proxy, the other one for
+        * the buffer.
+        */
+       while (*appctx->ctx.env.var) {
+               chunk_printf(&trash, "%s\n", *appctx->ctx.env.var);
+
+               if (bi_putchk(si_ic(si), &trash) == -1) {
+                       si_applet_cant_put(si);
+                       return 0;
+               }
+               if (appctx->st2 == STAT_ST_END)
+                       break;
+               appctx->ctx.env.var++;
+       }
+
+       /* dump complete */
+       return 1;
+}
+
 /* parse the "level" argument on the bind lines */
 static int bind_parse_level(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {