]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: lua: register and execute sample-fetches in LUA
authorThierry FOURNIER <tfournier@haproxy.com>
Mon, 16 Feb 2015 19:19:18 +0000 (20:19 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 28 Feb 2015 22:12:35 +0000 (23:12 +0100)
This patch permits to write LUA samples fetches. Note that
all the fethes declared trough LUA are automatically prefixed
by "lua.".

include/types/hlua.h
src/hlua.c

index 1241778114b027218f2b9f3b7f410ed4f337ebb6..a4d14442bdec63340002cdb8949491ef198d390c 100644 (file)
@@ -52,6 +52,15 @@ struct hlua_init_function {
        int function_ref;
 };
 
+/* This struct contains the lua data used to bind
+ * Lua function on HAProxy hook like sample-fetches
+ * or actions.
+ */
+struct hlua_function {
+       char *name;
+       int function_ref;
+};
+
 /* This struct contains the pointer provided on the most
  * of internal HAProxy calls during the processing of
  * rules, converters and sample-fetches. This struct is
index 22b6eb37e91c2436cbb1ed5c4df11a926cdaeb66..633e7a456d23ee0c28f3c254ea8879d3908e46c6 100644 (file)
@@ -1080,6 +1080,162 @@ static int hlua_register_task(lua_State *L)
        return 0;
 }
 
+/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
+ * doesn't allow "yield" functions because the HAProxy engine cannot
+ * resume sample-fetches.
+ */
+static int hlua_sample_fetch_wrapper(struct proxy *px, struct session *s, void *l7,
+                                     unsigned int opt, const struct arg *arg_p,
+                                     struct sample *smp, const char *kw, void *private)
+{
+       struct hlua_function *fcn = (struct hlua_function *)private;
+
+       /* If it is the first run, initialize the data for the call. */
+       if (s->hlua.state == HLUA_STOP) {
+               /* Check stack available size. */
+               if (!lua_checkstack(s->hlua.T, 2)) {
+                       send_log(px, LOG_ERR, "Lua sample-fetch '%s': full stack.", fcn->name);
+                       if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
+                               Alert("Lua sample-fetch '%s': full stack.\n", fcn->name);
+                       return 0;
+               }
+
+               /* Restore the function in the stack. */
+               lua_rawgeti(s->hlua.T, LUA_REGISTRYINDEX, fcn->function_ref);
+
+               /* push arguments in the stack. */
+               if (!hlua_txn_new(s->hlua.T, s, px, l7)) {
+                       send_log(px, LOG_ERR, "Lua sample-fetch '%s': full stack.", fcn->name);
+                       if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
+                               Alert("Lua sample-fetch '%s': full stack.\n", fcn->name);
+                       return 0;
+               }
+               s->hlua.nargs = 1;
+
+               /* push keywords in the stack. */
+               for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
+                       /* Check stack available size. */
+                       if (!lua_checkstack(s->hlua.T, 1)) {
+                               send_log(px, LOG_ERR, "Lua sample-fetch '%s': full stack.", fcn->name);
+                               if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
+                                       Alert("Lua sample-fetch '%s': full stack.\n", fcn->name);
+                               return 0;
+                       }
+                       if (!lua_checkstack(s->hlua.T, 1)) {
+                               send_log(px, LOG_ERR, "Lua sample-fetch '%s': full stack.", fcn->name);
+                               if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
+                                       Alert("Lua sample-fetch '%s': full stack.\n", fcn->name);
+                               return 0;
+                       }
+                       hlua_arg2lua(s->hlua.T, arg_p);
+                       s->hlua.nargs++;
+               }
+
+               /* Set the currently running flag. */
+               s->hlua.state = HLUA_RUN;
+       }
+
+       /* Execute the function. */
+       switch (hlua_ctx_resume(&s->hlua, 0)) {
+       /* finished. */
+       case HLUA_E_OK:
+               /* Convert the returned value in sample. */
+               hlua_lua2smp(s->hlua.T, -1, smp);
+               lua_pop(s->hlua.T, 1);
+
+               /* Set the end of execution flag. */
+               smp->flags &= ~SMP_F_MAY_CHANGE;
+               return 1;
+
+       /* yield. */
+       case HLUA_E_AGAIN:
+               send_log(px, LOG_ERR, "Lua sample-fetch '%s': cannot use yielded functions.", fcn->name);
+               if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
+                       Alert("Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
+               return 0;
+
+       /* finished with error. */
+       case HLUA_E_ERRMSG:
+               /* Display log. */
+               send_log(px, LOG_ERR, "Lua sample-fetch '%s': %s.", fcn->name, lua_tostring(s->hlua.T, -1));
+               if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
+                       Alert("Lua sample-fetch '%s': %s.\n", fcn->name, lua_tostring(s->hlua.T, -1));
+               lua_pop(s->hlua.T, 1);
+               return 0;
+
+       case HLUA_E_ERR:
+               /* Display log. */
+               send_log(px, LOG_ERR, "Lua sample-fetch '%s' returns an unknown error.", fcn->name);
+               if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
+                       Alert("Lua sample-fetch '%s': returns an unknown error.\n", fcn->name);
+
+       default:
+               return 0;
+       }
+}
+
+/* This fucntion is an LUA binding used for registering
+ * "sample-fetch" functions. It expects a converter name used
+ * in the haproxy configuration file, and an LUA function.
+ */
+__LJMP static int hlua_register_fetches(lua_State *L)
+{
+       const char *name;
+       int ref;
+       int len;
+       struct sample_fetch_kw_list *sfk;
+       struct hlua_function *fcn;
+
+       MAY_LJMP(check_args(L, 2, "register_fetches"));
+
+       /* First argument : sample-fetch name. */
+       name = MAY_LJMP(luaL_checkstring(L, 1));
+
+       /* Second argument : lua function. */
+       ref = MAY_LJMP(hlua_checkfunction(L, 2));
+
+       /* Allocate and fill the sample fetch keyword struct. */
+       sfk = malloc(sizeof(struct sample_fetch_kw_list) +
+                    sizeof(struct sample_fetch) * 2);
+       if (!sfk)
+               WILL_LJMP(luaL_error(L, "lua out of memory error."));
+       fcn = malloc(sizeof(*fcn));
+       if (!fcn)
+               WILL_LJMP(luaL_error(L, "lua out of memory error."));
+
+       /* Fill fcn. */
+       fcn->name = strdup(name);
+       if (!fcn->name)
+               WILL_LJMP(luaL_error(L, "lua out of memory error."));
+       fcn->function_ref = ref;
+
+       /* List head */
+       sfk->list.n = sfk->list.p = NULL;
+
+       /* sample-fetch keyword. */
+       len = strlen("lua.") + strlen(name) + 1;
+       sfk->kw[0].kw = malloc(len);
+       if (!sfk->kw[0].kw)
+               return luaL_error(L, "lua out of memory error.");
+
+       snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
+       sfk->kw[0].process = hlua_sample_fetch_wrapper;
+       sfk->kw[0].arg_mask = ARG5(0,STR,STR,STR,STR,STR);
+       sfk->kw[0].val_args = NULL;
+       sfk->kw[0].out_type = SMP_T_STR;
+       sfk->kw[0].use = SMP_USE_HTTP_ANY;
+       sfk->kw[0].val = 0;
+       sfk->kw[0].private = fcn;
+
+       /* End of array. */
+       memset(&sfk->kw[1], 0, sizeof(struct sample_fetch));
+
+       /* Register this new fetch. */
+       sample_register_fetches(sfk);
+
+       return 0;
+}
+
 /* This function is called by the main configuration key "lua-load". It loads and
  * execute an lua file during the parsing of the HAProxy configuration file. It is
  * the main lua entry point.
@@ -1217,6 +1373,7 @@ void hlua_init(void)
        /* Register special functions. */
        hlua_class_function(gL.T, "register_init", hlua_register_init);
        hlua_class_function(gL.T, "register_task", hlua_register_task);
+       hlua_class_function(gL.T, "register_fetches", hlua_register_fetches);
 
        /* Store the table __index in the metable. */
        lua_settable(gL.T, -3);