When entering a payload while in interactive mode, the prompt will change from
"> " to "+ ".
+Most commands should run rapidly before reporting their final status. Some
+commands though may take longer to wait for external events. By default, the
+handler is interrupted as soon as the CLI client disconnects which is the
+safest behavior. However, this causes issues with utilities such as 'socat'
+which close their output channel only, as haproxy is unable to differentiate
+between a full and a partial close. These commands may support an extra
+argument to run in the so-called uninterruptible execution mode. To prevent
+excessive usage, the number of concurrent uninterruptible jobs is fixed to a
+low value and extra requests will be rejected with an error.
+
It is important to understand that when multiple haproxy processes are started
on the same sockets, any process may pick up the request and will output its
own stats.
if the command is terminated or the session released */
struct cli_kw *kw; /* the keyword being processed */
struct mt_list sess_el; /* attach point in global <cli_session_list> */
+ uint cmd_flags; /* flags for the active command */
} cli_ctx; /* context dedicated to the CLI applet */
struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */
struct cli_kw* cli_find_kw_exact(char **args);
void cli_list_keywords(void);
+int cli_inc_unintr(struct appctx *appctx);
+void cli_dec_unintr(struct appctx *appctx);
+
int cli_has_level(struct appctx *appctx, int level);
int cli_parse_default(char **args, char *payload, struct appctx *appctx, void *private);
/* Currently active CLI sessions. */
static struct mt_list cli_session_list = MT_LIST_HEAD_INIT(cli_session_list);
+/* Limit of concurrent uninterruptible jobs. */
+#define CLI_MAX_JOBS_UNINTR 3
+/* Current number of concurrent uninterruptible jobs. */
+static uint cli_jobs_unintr = 0;
+
+/* Prepare for the execution of a new uninterruptible job.
+ * Returns 0 on success or non zero if concurrent job limit exceeded.
+ */
+int cli_inc_unintr(struct appctx *appctx)
+{
+ if (HA_ATOMIC_FETCH_ADD(&cli_jobs_unintr, 1) >= CLI_MAX_JOBS_UNINTR) {
+ HA_ATOMIC_DEC(&cli_jobs_unintr);
+ return 1;
+ }
+
+ appctx->cli_ctx.cmd_flags |= CLI_CMD_FL_UNINTR;
+ return 0;
+}
+
+/* Notify about the end of an uninterruptible job. */
+void cli_dec_unintr(struct appctx *appctx)
+{
+ if (!(appctx->cli_ctx.cmd_flags & CLI_CMD_FL_UNINTR))
+ return;
+
+ HA_ATOMIC_DEC(&cli_jobs_unintr);
+ appctx->cli_ctx.cmd_flags &= ~CLI_CMD_FL_UNINTR;
+}
+
/* CLI context for the "show fd" command */
/* flags for show_fd_ctx->show_mask */
#define CLI_SHOWFD_F_PI 0x00000001 /* pipes */
appctx->cli_ctx.kw = NULL;
appctx->cli_ctx.io_handler = NULL;
appctx->cli_ctx.io_release = NULL;
+ appctx->cli_ctx.cmd_flags = 0;
}
/* Processes the CLI interpreter on the stats socket. This function is called
appctx->cli_ctx.payload = BUF_NULL;
appctx->cli_ctx.max_payload_sz = global.tune.cli_max_payload_sz;
MT_LIST_APPEND(&cli_session_list, &appctx->cli_ctx.sess_el);
+ appctx->cli_ctx.cmd_flags = 0;
/* Wakeup the applet ASAP. */
applet_need_more_data(appctx);